支援版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

REINDEX

REINDEX — 重建索引

概要

REINDEX [ ( option [, ...] ) ] { INDEX | TABLE | SCHEMA } [ CONCURRENTLY ] name
REINDEX [ ( option [, ...] ) ] { DATABASE | SYSTEM } [ CONCURRENTLY ] [ name ]

where option can be one of:

    CONCURRENTLY [ boolean ]
    TABLESPACE new_tablespace
    VERBOSE [ boolean ]

描述

REINDEX 使用索引的資料表中所儲存的資料來重建索引,取代舊的索引副本。在幾種情況下會使用 REINDEX

  • 索引已損毀,不再包含有效的資料。雖然理論上這不應該發生,但實際上,由於軟體錯誤或硬體故障,索引可能會損毀。REINDEX 提供了一種恢復方法。

  • 索引已經變得膨脹,也就是說,它包含許多空的或幾乎是空的頁面。在某些不常見的存取模式下,PostgreSQL 中的 B-tree 索引可能會發生這種情況。REINDEX 提供了一種方法,可以透過編寫一個沒有無效頁面的新版本的索引來減少索引的空間消耗。有關更多資訊,請參閱第 24.2 節

  • 您已變更索引的儲存參數(例如 fillfactor),並希望確保變更已完全生效。

  • 如果使用 CONCURRENTLY 選項建立索引失敗,則此索引將保持為無效。此類索引沒有用,但使用 REINDEX 重建它們會很方便。請注意,只有 REINDEX INDEX 才能在無效的索引上執行並行建立。

參數

INDEX

重建指定的索引。當用於分割索引時,REINDEX 的此形式不能在交易區塊內執行。

TABLE

重建指定資料表的所有索引。如果該資料表有第二個TOAST資料表,則也會重新索引。當用於分割資料表時,REINDEX 的此形式不能在交易區塊內執行。

SCHEMA

重建指定綱要的所有索引。如果此綱要的資料表有第二個TOAST資料表,則也會重新索引。共用系統目錄上的索引也會被處理。 REINDEX 的此形式不能在交易區塊內執行。

DATABASE

重建目前資料庫中的所有索引,除了系統目錄。系統目錄上的索引不會被處理。REINDEX 的此形式不能在交易區塊內執行。

SYSTEM

重建目前資料庫中系統目錄上的所有索引。包括共用系統目錄上的索引。不會處理使用者資料表上的索引。REINDEX 的此形式不能在交易區塊內執行。

名稱

要重新索引的特定索引、資料表或資料庫的名稱。索引和資料表名稱可以是綱要限定的。目前,REINDEX DATABASEREINDEX SYSTEM 只能重新索引目前的資料庫。它們的參數是可選的,並且必須與目前資料庫的名稱相符。

CONCURRENTLY

當使用此選項時,PostgreSQL 將重建索引,而不會採取任何會阻止同時在資料表上插入、更新或刪除的鎖定;而標準的索引重建會鎖定資料表上的寫入(但不鎖定讀取),直到完成為止。使用此選項時,需要注意以下幾個注意事項 — 請參閱下面的並行重建索引

對於臨時資料表,REINDEX 始終是非並行的,因為沒有其他會話可以存取它們,並且非並行重新索引更便宜。

TABLESPACE

指定索引將在新的資料表空間上重建。

VERBOSE

在重新索引每個索引時列印進度報告。

boolean

指定是否應開啟或關閉所選選項。您可以寫入 TRUEON1 來啟用該選項,並寫入 FALSEOFF0 來停用它。 也可以省略 boolean 值,在這種情況下,假定為 TRUE

new_tablespace

將在其中重建索引的資料表空間。

注意事項

如果您懷疑使用者資料表上的索引已損毀,您可以簡單地重建該索引,或重建資料表上的所有索引,使用 REINDEX INDEXREINDEX TABLE

如果您需要從系統資料表上的索引損毀中恢復,事情會變得更加困難。在這種情況下,對於系統來說,不使用任何可疑索引本身非常重要。(實際上,在這種情況下,您可能會發現伺服器進程在啟動時立即崩潰,因為它們依賴於損毀的索引。)為了安全地恢復,必須使用 -P 選項啟動伺服器,這可以防止它使用索引進行系統目錄查找。

其中一種方法是關閉伺服器,然後使用包含 -P 選項的命令列,啟動單一使用者 PostgreSQL 伺服器。然後,可以發出 REINDEX DATABASEREINDEX SYSTEMREINDEX TABLEREINDEX INDEX,具體取決於您要重建的程度。如果無法確定,請使用 REINDEX SYSTEM 來選擇重建資料庫中的所有系統索引。接著,結束單一使用者伺服器會話,然後重新啟動一般伺服器。請參閱 postgres 參考頁面,以取得有關如何與單一使用者伺服器介面互動的更多資訊。

或者,可以使用包含 -P 在其命令列選項中的方式,啟動一般伺服器會話。這樣做的方法因客戶端而異,但在所有基於 libpq 的客戶端中,都可以在啟動客戶端之前,將 PGOPTIONS 環境變數設定為 -P。請注意,雖然此方法不需要鎖定其他客戶端,但最好還是阻止其他使用者連線到損壞的資料庫,直到修復完成為止。

REINDEX 類似於刪除並重新建立索引,因為索引內容是從頭開始重建的。但是,鎖定的考量因素卻大不相同。REINDEX 會鎖定寫入,但不會鎖定索引父表格的讀取。它還會在正在處理的特定索引上取得 ACCESS EXCLUSIVE 鎖定,這會阻止嘗試使用該索引的讀取。特別是,查詢計畫器會嘗試在表格的每個索引上取得 ACCESS SHARE 鎖定,無論查詢為何,因此 REINDEX 實際上會阻止任何查詢,除了某些計畫已被快取且未使用此索引的預先準備查詢之外。相反,DROP INDEX 會暫時在父表格上取得 ACCESS EXCLUSIVE 鎖定,從而阻止寫入和讀取。隨後的 CREATE INDEX 會鎖定寫入,但不會鎖定讀取;由於索引不存在,因此沒有讀取會嘗試使用它,這表示不會有任何鎖定,但讀取可能會被迫進行昂貴的循序掃描。

REINDEX 執行時,search_path 會暫時變更為 pg_catalog, pg_temp

為單個索引或表格重建索引需要對該表格具有 MAINTAIN 權限。請注意,雖然對分割索引或表格執行 REINDEX 需要對分割表格具有 MAINTAIN 權限,但此類指令在處理各個分割區時會跳過權限檢查。為綱要或資料庫重建索引需要成為該綱要或資料庫的擁有者,或擁有 pg_maintain 角色的權限。特別要注意的是,因此非超級使用者可以重建其他使用者擁有的表格的索引。但是,作為一個特例,REINDEX DATABASEREINDEX SCHEMAREINDEX SYSTEM 將跳過共享目錄上的索引,除非使用者具有目錄的 MAINTAIN 權限。

分別使用 REINDEX INDEXREINDEX TABLE 支援為分割索引或分割表格重建索引。指定分割關係的每個分割區都會在單獨的交易中重建索引。在處理分割表格或索引時,這些指令不能在交易區塊內使用。

在分割索引或表格上使用 REINDEXTABLESPACE 子句時,僅會更新葉分割區的表格空間參考。由於分割索引不會更新,因此建議單獨對它們使用 ALTER TABLE ONLY,以便附加的任何新分割區都繼承新的表格空間。如果失敗,可能沒有將所有索引移動到新的表格空間。重新執行指令將重建所有葉分割區,並將先前未處理的索引移動到新的表格空間。

如果將 SCHEMADATABASESYSTEMTABLESPACE 一起使用,則會跳過系統關係,並且會產生單個 WARNING。將重建 TOAST 表格上的索引,但不會將它們移動到新的表格空間。

並行重建索引

重建索引可能會干擾資料庫的常規運作。通常,PostgreSQL 會鎖定要重建其索引的表格,以防止寫入,並以單一的表格掃描來執行整個索引建立。其他交易仍然可以讀取表格,但是如果它們嘗試在表格中插入、更新或刪除列,則它們將被鎖定,直到索引重建完成。如果系統是正在運作的生產資料庫,這可能會產生嚴重的影響。非常大的表格可能需要數小時才能建立索引,即使對於較小的表格,索引重建也可能會鎖定寫入者一段時間,而這段時間對於生產系統來說是無法接受的。

PostgreSQL 支援以最小的寫入鎖定來重建索引。透過指定 REINDEXCONCURRENTLY 選項來叫用此方法。當使用此選項時,PostgreSQL 必須對每個需要重建的索引執行兩次表格掃描,並等待可能使用該索引的所有現有交易終止。此方法需要比標準索引重建更多的工作量,並且完成時間顯著增加,因為它需要等待可能修改索引的未完成交易。但是,由於它允許在重建索引時繼續執行常規運作,因此此方法適用於在生產環境中重建索引。當然,索引重建所造成的額外 CPU、記憶體和 I/O 負載可能會降低其他運作的速度。

並行重建索引會發生以下步驟。每個步驟都在單獨的交易中執行。如果要重建多個索引,則每個步驟都會在移至下一個步驟之前,迴圈遍歷所有索引。

  1. 新的暫時索引定義會新增至目錄 pg_index。此定義將用於替換舊索引。會在要重建索引的索引及其相關表格上取得工作階段層級的 SHARE UPDATE EXCLUSIVE 鎖定,以防止在處理過程中進行任何綱要修改。

  2. 為每個新索引完成建立索引的第一個步驟。建立索引後,其標誌 pg_index.indisready 會切換為 true,使其可以插入,一旦執行建立的交易完成,其他工作階段就可以看到它。此步驟針對每個索引在單獨的交易中完成。

  3. 然後,執行第二個步驟,以新增在執行第一個步驟時新增的元組。此步驟也針對每個索引在單獨的交易中完成。

  4. 所有參照到索引的約束條件都會變更為參照新的索引定義,並且索引名稱也會變更。此時,新的索引的 pg_index.indisvalid 會切換為 true,而舊的索引則會切換為 false,並且會執行快取失效,導致所有參照到舊索引的工作階段失效。

  5. 舊的索引的 pg_index.indisready 會切換為 false,以防止任何新的元組插入,並在等待可能參照舊索引的執行中查詢完成後執行。

  6. 舊的索引會被捨棄。索引和資料表的 SHARE UPDATE EXCLUSIVE 工作階段鎖定會被釋放。

如果在重建索引時發生問題,例如唯一索引中出現唯一性衝突,REINDEX 指令會失敗,但會留下一個 invalid 的新索引以及先前的索引。由於這個索引可能不完整,因此在查詢時會被忽略;但是,它仍然會消耗更新的額外負擔。psql \d 指令會將此類索引報告為 INVALID

postgres=# \d tab
       Table "public.tab"
 Column |  Type   | Modifiers
--------+---------+-----------
 col    | integer |
Indexes:
    "idx" btree (col)
    "idx_ccnew" btree (col) INVALID

如果標記為 INVALID 的索引後綴為 ccnew,則它對應於並行操作期間建立的暫時索引,建議的恢復方法是使用 DROP INDEX 捨棄它,然後再次嘗試 REINDEX CONCURRENTLY。如果無效索引的後綴改為 ccold,則它對應於無法捨棄的原始索引;建議的恢復方法是直接捨棄該索引,因為重建已成功。

一般索引建立允許在同一個資料表上同時進行其他一般索引建立,但一次只能在一個資料表上進行一個並行索引建立。在這兩種情況下,都不允許同時對資料表進行其他類型的結構描述修改。另一個區別是,一般 REINDEX TABLEREINDEX INDEX 指令可以在事務區塊內執行,但 REINDEX CONCURRENTLY 不能。

與任何長時間執行的事務一樣,資料表上的 REINDEX 會影響並行 VACUUM 可以從任何其他資料表中移除哪些元組。

REINDEX SYSTEM 不支援 CONCURRENTLY,因為系統目錄無法並行重建索引。

此外,排除約束的索引無法並行重建索引。如果在此指令中直接命名此類索引,則會引發錯誤。如果具有排除約束索引的資料表或資料庫被並行重建索引,則會跳過這些索引。(可以使用沒有 CONCURRENTLY 選項來重建這些索引。)

執行 REINDEX 的每個後端都會在 pg_stat_progress_create_index 檢視表中報告其進度。有關詳細資訊,請參閱 第 27.4.4 節

範例

重建單個索引

REINDEX INDEX my_index;

重建資料表 my_table 上的所有索引

REINDEX TABLE my_table;

重建特定資料庫中的所有索引,而不信任系統索引已有效

$ export PGOPTIONS="-P"
$ psql broken_db
...
broken_db=> REINDEX DATABASE broken_db;
broken_db=> \q

重建資料表的索引,在重建索引期間不封鎖相關關係上的讀寫操作

REINDEX TABLE CONCURRENTLY my_broken_table;

相容性

SQL 標準中沒有 REINDEX 指令。

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用此表單報告文件問題。