全部產品
Search
文件中心

PolarDB:REINDEX

更新時間:Jul 06, 2024

本文介紹了REINDEX的文法、參數以及樣本等內容。

文法

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

    其中 選項 可以是以下之一:

        VERBOSE

簡介

REINDEX使用索引的表裡儲存的資料重建一個索引, 並且替換該索引的舊拷貝。有一些情境需要使用REINDEX

  • 一個索引已經損壞,並且不再包含合法資料。儘管理論上這不會發生, 實際上索引會因為軟體缺陷或硬體失效損壞。 REINDEX提供了一種恢複方法。

  • 一個索引變得“臃腫”,其中包含很多空的或者近乎為空白的頁面。 PolarDB中的 B-樹索引在特定的非常規訪問模式下可能會發生這種情況。REINDEX 提供了一種方法來減少索引的空間消耗,即製造一個新版本的索引,其中沒有死亡頁面。

  • 修改了一個索引的儲存參數(例如填滿因數),並且希望確保這種修改完全生效。

  • 如果索引在用CONCURRENTLY選項建立失敗,該索引保留為一個“invalid”。 這類索引是無用的,但是可以方便地用REINDEX來重建它們。

    說明

    只有REINDEX INDEX可以在無效的索引上執行並發建立。

參數

  • INDEX重新建立指定的索引。

  • TABLE重新建立指定表的所有索引。如果該表有一個二級 “TOAST”表,它也會被重新索引。

  • SCHEMA重建指定方案的所有索引。如果這個方案中的一個表有次級的“TOAST”表,它也會被重建索引。共用系統目錄上的索引也會被處理。這種形式的REINDEX不能在事務塊內執行。

  • DATABASE重新建立當前資料庫內的所有索引。共用的系統目錄上的索引也會被處理。這種形式的REINDEX不能在一個事務塊內執行。

  • SYSTEM重新建立當前資料庫中在系統目錄上的所有索引。共用系統目錄上的索引也被包括在內。使用者表上的索引則不會被處理。這種形式的 REINDEX不能在一個事務塊內執行。

  • name要被重索引的特定索引、表或者資料庫的名字。索引和表名可以被模式限定。當前,REINDEX DATABASEREINDEX SYSTEM只能重索引當前資料庫,因此,它們的參數必須匹配當前資料庫的名稱。

  • CONCURRENTLY使用此選項時,PolarDB 將重建索引,而不在表上採取任何阻止並發插入、更新或刪除的鎖; 標準的索引重建將會鎖定表上的寫操作(而不是讀操作),直到它完成。

  • 對於暫存資料表,REINDEX始終是非並發的,因為沒有其他會話可以訪問它們,並且非並發重新索引更便宜。

  • VERBOSE在每個索引被重建時列印進度報告。

說明

如果懷疑一個使用者表上的索引損壞,可以使用 REINDEX INDEX或者 REINDEX TABLE簡單地重建該索引或者表上的所有索引。

如果你需要從一個系統資料表上的索引損壞中恢複,就更困難一些。在這種情況下,對系統來說重要的是沒有使用過任何可疑的索引本身( 實際上,在這種情境中,你可能會探索服務器進程會在啟動時立刻崩潰, 這是因為對於損壞的索引的依賴)。要安全地恢複,伺服器必須用 -P選項啟動,這將阻止它使用索引來進行系統目錄尋找。

這樣做的一種方法是關閉伺服器,並且啟動一個單使用者的 PolarDB伺服器,在其命令列中包括-P選項。然後,可以發出 REINDEX DATABASEREINDEX SYSTEMREINDEX TABLE或者REINDEX INDEX, 具體使用哪個命令取決於你想要重構多少東西。如果有疑問,可以使用 REINDEX SYSTEM來選擇重建資料庫中的所有系統索引。 然後退出單使用者服務器會話並且重啟常規的伺服器。更多關於如何與單使用者服務器介面互動的內容請見postgres參考頁。

在另一種方法中,可以開始一個常規的伺服器會話,在其命令列選項中包括-P。這樣做的方法與用戶端有關,但是在所有基於libpq的用戶端中都可以在開始用戶端之前設定PGOPTIONS環境變數為-P。 注意雖然這種方法不要求用鎖排斥其他用戶端,在修複完成之前避免其他使用者串連到受損的資料庫才是更加明智的。

REINDEX類似於刪除索引並且重建索引,在其中索引內容會被從頭開始建立。不過,鎖定方面的考慮卻相當不同。 REINDEX會用鎖排斥寫,但不會排斥在索引的父表上的讀。 它也會在被處理的索引上取得一個獨佔鎖定,該鎖將會阻塞對該索引的使用嘗試。 相反,DROP INDEX 會暫時在附表上取得一個獨佔鎖定,阻塞寫和讀。後續的CREATE INDEX會排斥寫但不排斥讀,由於該索引不存在,所以不會有讀取它的嘗試,這意味著不會有阻塞但是讀操作可能被強製成昂貴的順序掃描。

重索引單獨一個索引或者表要求使用者是該索引或表的擁有者。對方案或資料庫重建索引要求是該方案或者資料庫的擁有者。請特別注意,因此非超級使用者有時無法重建其他使用者擁有的表上的索引。不過,作為一種特例,當一個非超級使用者發出REINDEX DATABASEREINDEX SCHEMA或者REINDEX SYSTEM時,共用目錄上的索引將被跳過,除非該使用者擁有該目錄(通常不會是這樣)。當然,超級使用者總是可以重建所有的索引。

不支援重建分區表的索引或者分區索引。不過可以單獨為每個分區重建索引。

並發重建索引

重建索引可能會影響資料庫的常規操作。通常PolarDB會鎖定重建的表以防止寫操作,並通過單次掃描表來執行整個索引構建。 其他事務仍可以讀取表,但如果它們嘗試在表中插入、更新或刪除行,它們將被阻止,直到索引重建完成。 如果系統是即時生產資料庫,這可能會產生嚴重影響。非常大的表可能需要幾個小時才能編製索引,即使對於較小的表,索引重建也會鎖定編寫器,這些時間段對於生產系統來說是不可接受的。

PolarDB支援以最少的寫入鎖定來重建索引。此方法通過指定REINDEXCONCURRENTLY選項來調用。 使用此選項時,PolarDB必須對需要重建的每個索引執行兩次表掃描,並等待可能使用索引的所有現有事務的終止。 此方法需要比標準索引重建更大的工作量,並且需要相當長的時間才能完成,因為它需要等待可能修改索引的未完成的事務。 但是,由於它允許在重建索引時繼續正常操作,此方法可用於在生產環境中重建索引。當然,重建索引所需的額外 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 SYSTEM 不支援 CONCURRENTLY 因為系統目錄不能並發重新索引。

此外,排除約束的索引不能並發重新編製索引。 如果此命令中直接命名了這樣的索引,則會引發錯誤。 如果並發重新編製具有排除約束索引的表或資料庫,將跳過這些索引。 (它可以不使用CONCURRENTLY選項來重新編製這樣的索引)。

樣本

重建單個索引:

    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;