支援的版本:目前 (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

CREATE INDEX

CREATE INDEX — 定義一個新的索引

概要

CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
    ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
    [ INCLUDE ( column_name [, ...] ) ]
    [ NULLS [ NOT ] DISTINCT ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ TABLESPACE tablespace_name ]
    [ WHERE predicate ]

描述

CREATE INDEX 在指定關聯的指定欄位上建立索引,該關聯可以是表格或實體化檢視表。索引主要用於提升資料庫效能(儘管不當使用可能會導致效能降低)。

索引的索引鍵欄位指定為欄位名稱,或者指定為括號中撰寫的運算式。如果索引方法支援多欄位索引,則可以指定多個欄位。

索引欄位可以是從表格列的一或多個欄位值計算而來的運算式。此功能可用於根據基本資料的某種轉換快速存取資料。例如,在 upper(col) 上計算的索引將允許子句 WHERE upper(col) = 'JIM' 使用索引。

PostgreSQL 提供 B-tree、hash、GiST、SP-GiST、GIN 和 BRIN 等索引方法。使用者也可以定義自己的索引方法,但這相當複雜。

當存在 WHERE 子句時,會建立部分索引。部分索引是一種僅包含表格一部分項目的索引,通常是比表格其餘部分更適合建立索引的部分。例如,如果您有一個包含已計費和未計費訂單的表格,其中未計費訂單僅佔總表格的一小部分,但卻是經常使用的部分,則可以透過僅在該部分上建立索引來提高效能。另一個可能的應用是將 WHEREUNIQUE 結合使用,以強制表格子集的唯一性。請參閱第 11.8 節以取得更多討論。

WHERE 子句中使用的運算式只能參考基礎表格的欄位,但它可以使用所有欄位,而不僅僅是被建立索引的欄位。目前,子查詢和聚合運算式在 WHERE 中也是禁止的。相同的限制適用於作為運算式的索引欄位。

索引定義中使用的所有函式和運算子都必須是不可變的,也就是說,它們的結果必須僅取決於它們的引數,而絕不能取決於任何外部影響(例如另一個表格的內容或目前時間)。此限制確保索引的行為良好定義。若要在索引運算式或 WHERE 子句中使用使用者定義的函式,請記住在建立函式時將其標記為不可變。

參數

UNIQUE

導致系統在建立索引時(如果資料已存在)以及每次新增資料時檢查表格中是否有重複的值。嘗試插入或更新會導致重複項目的資料將會產生錯誤。

將唯一索引套用到分割表格時,會套用其他限制;請參閱 CREATE TABLE

CONCURRENTLY

使用此選項時,PostgreSQL 將建立索引,而不會採用任何防止同時在表格上進行插入、更新或刪除的鎖定;而標準索引建立會在完成之前鎖定表格上的寫入(但不會鎖定讀取)。使用此選項時,需要注意幾個注意事項 - 請參閱下方的同時建立索引

對於暫存表格,CREATE INDEX 始終是非同步的,因為沒有其他工作階段可以存取它們,並且非同步索引建立成本較低。

IF NOT EXISTS

如果已存在具有相同名稱的關聯,則不要擲回錯誤。在這種情況下會發出通知。請注意,無法保證現有的索引與將建立的索引相似。指定 IF NOT EXISTS 時,需要索引名稱。

INCLUDE

可選的 INCLUDE 子句指定一個欄位清單,這些欄位將作為非索引鍵欄位包含在索引中。非索引鍵欄位不能用於索引掃描搜尋限定條件,並且在索引強制執行的任何唯一性或排除限制的目的中將被忽略。但是,索引專用掃描可以傳回非索引鍵欄位的內容,而無需訪問索引的表格,因為它們可以直接從索引項目中取得。因此,新增非索引鍵欄位允許索引專用掃描用於否則無法使用它們的查詢。

謹慎地將非索引鍵欄位新增到索引中是明智的,尤其是寬欄位。如果索引元組超過索引類型允許的最大大小,則資料插入將會失敗。在任何情況下,非索引鍵欄位都會重複索引表格中的資料,並使索引的大小膨脹,因此可能會減慢搜尋速度。此外,B-tree 重複資料刪除永遠不會用於具有非索引鍵欄位的索引。

INCLUDE 子句中列出的欄位不需要適當的運算子類別;該子句可以包含其資料類型沒有為給定存取方法定義運算子類別的欄位。

由於運算式不能用於索引專用掃描,因此不支援運算式作為包含的欄位。

目前,B-tree、GiST 和 SP-GiST 索引存取方法支援此功能。在這些索引中,INCLUDE 子句中列出的欄位值包含在對應於堆積元組的葉元組中,但不包含在用於樹狀結構導覽的上層索引項目中。

名稱

要建立的索引名稱。這裡不能包含綱要名稱;索引永遠會在其父表格的相同綱要中建立。索引名稱必須與該綱要中的任何其他關聯(表格、序列、索引、檢視表、實體化檢視表或外部表格)的名稱不同。如果省略名稱,PostgreSQL 會根據父表格的名稱和被索引的欄位名稱,選擇一個合適的名稱。

ONLY

如果表格是分割的,表示不要遞迴地在分割區上建立索引。預設是遞迴。

table_name

要建立索引的表格名稱(可以包含綱要限定詞)。

method

要使用的索引方法名稱。選項包括 btreehashgistspgistginbrin 或使用者安裝的存取方法,例如 bloom。預設方法是 btree

column_name

表格中欄位的名稱。

expression

基於表格中一個或多個欄位的運算式。如語法所示,運算式通常必須用括號括起來。但是,如果運算式具有函數呼叫的形式,則可以省略括號。

collation

要用於索引的定序名稱。預設情況下,索引使用為要索引的欄位宣告的定序,或要索引的運算式的結果定序。具有非預設定序的索引對於涉及使用非預設定序的運算式的查詢很有用。

opclass

運算子類別的名稱。詳情請參閱下文。

opclass_parameter

運算子類別參數的名稱。詳情請參閱下文。

ASC

指定遞增排序順序(這是預設值)。

DESC

指定遞減排序順序。

NULLS FIRST

指定 null 值在非 null 值之前排序。這是指定 DESC 時的預設值。

NULLS LAST

指定 null 值在非 null 值之後排序。這是未指定 DESC 時的預設值。

NULLS DISTINCT
NULLS NOT DISTINCT

指定對於唯一索引,是否應將 null 值視為不同(不相等)。預設情況下,它們是不同的,因此唯一索引可以在欄位中包含多個 null 值。

storage_parameter

索引方法特定的儲存參數的名稱。詳情請參閱下文 索引儲存參數

tablespace_name

要在其中建立索引的表格空間。如果未指定,則參考 default_tablespace,對於臨時表格上的索引,則參考 temp_tablespaces

predicate

部分索引的限制運算式。

索引儲存參數

可選的 WITH 子句指定索引的儲存參數。每種索引方法都有其自身的一組允許的儲存參數。B-tree、hash、GiST 和 SP-GiST 索引方法都接受此參數

fillfactor (integer) #

索引的 fillfactor 是一個百分比,它決定了索引方法將嘗試將索引頁面填滿的程度。對於 B-tree,葉子頁面在初始索引構建期間以及在右側擴展索引(新增新的最大鍵值)時會填充到此百分比。如果頁面隨後變得完全填滿,它們將被分割,導致磁碟上的索引結構碎片化。B-tree 使用 90 的預設 fillfactor,但可以選擇從 10 到 100 的任何整數值。

預期會進行大量插入和/或更新的表格上的 B-tree 索引可以受益於在 CREATE INDEX 時設定較低的 fillfactor(在批量載入到表格後)。50 - 90 範圍內的值可以有效地平滑 B-tree 索引早期生命週期中頁面分割的速率(像這樣降低 fillfactor 甚至可能降低頁面分割的絕對數量,儘管這種效果高度依賴於工作負載)。第 64.1.4.2 節中描述的 B-tree 自下而上索引刪除技術取決於在頁面上有一些額外空間來儲存額外的元組版本,因此可能會受到 fillfactor 的影響(儘管效果通常不顯著)。

在其他特定情況下,在 CREATE INDEX 時將 fillfactor 增加到 100 可能很有用,作為最大化空間利用率的一種方式。只有當你完全確定表格是靜態的(即,它永遠不會受到插入或更新的影響)時,才應該考慮這樣做。否則,fillfactor 設定為 100 可能會損害效能:即使是少量的更新或插入也會導致突然出現大量頁面分割。

其他索引方法以不同但大致類似的方式使用 fillfactor;預設 fillfactor 因方法而異。

B-tree 索引另外接受此參數

deduplicate_items (boolean) #

控制 第 64.1.4.3 節中描述的 B-tree 重複資料刪除技術的使用。設定為 ONOFF 以啟用或停用最佳化。(允許使用 第 19.1 節中描述的 ONOFF 的替代拼寫。)預設值為 ON

注意

透過 ALTER INDEX 關閉 deduplicate_items 會阻止未來的插入觸發重複資料刪除,但本身不會使現有的發佈清單元組使用標準元組表示形式。

GiST 索引另外接受此參數

buffering (enum) #

決定是否使用第 64.2.4.1 節中描述的緩衝建置技術來建立索引。使用 OFF 時,會停用緩衝;使用 ON 時,會啟用緩衝;使用 AUTO 時,預設為停用,但一旦索引大小達到 effective_cache_size 時,會動態開啟。預設值為 AUTO。請注意,如果可以進行排序建置,則會使用排序建置,而不是緩衝建置,除非指定 buffering=ON

GIN 索引接受不同的參數

fastupdate (boolean) #

此設定控制 第 64.4.4.1 節中描述的快速更新技術的使用。它是一個布林參數:ON 啟用快速更新,OFF 停用它。預設值為 ON

注意

透過 ALTER INDEX 關閉 fastupdate 會阻止未來的插入進入待處理索引條目的清單,但本身不會清除先前的條目。 您可能需要對表進行 VACUUM 或在之後呼叫 gin_clean_pending_list 函數,以確保待處理清單為空。

gin_pending_list_limit (integer) #

自訂 gin_pending_list_limit 參數。 此值以 KB 為單位指定。

BRIN索引接受不同的參數

pages_per_range (integer) #

定義組成 BRIN 索引中每個條目的區塊範圍的資料表區塊數量。BRIN索引(更多詳細資訊請參閱第 64.5.1 節)。 預設值為 128

autosummarize (boolean) #

定義每當在下一個頁面範圍上偵測到插入時,是否將摘要運行排隊到上一個頁面範圍。 有關更多詳細資訊,請參閱第 64.5.1.1 節。 預設值為 off

並行建立索引

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

PostgreSQL 支援在不鎖定寫入的情況下建立索引。 透過指定 CREATE INDEXCONCURRENTLY 選項來調用此方法。 使用此選項時,PostgreSQL 必須對資料表執行兩次掃描,此外,它還必須等待所有可能修改或使用索引的現有交易終止。 因此,此方法需要比標準索引建置更多的工作量,並且完成的時間明顯更長。 但是,由於它允許在建立索引時繼續進行常規操作,因此此方法可用於在生產環境中新增索引。 當然,建立索引所產生的額外 CPU 和 I/O 負載可能會降低其他操作的速度。

在並行索引建置中,索引實際上是作為 無效 索引輸入到一個交易中的系統目錄中,然後在另外兩個交易中發生兩次資料表掃描。 在每次資料表掃描之前,索引建置必須等待已修改資料表的現有交易終止。 在第二次掃描之後,索引建置必須等待任何具有早於第二次掃描的快照(請參閱第 13 章)的交易終止,包括在其他資料表上並行索引建置的任何階段所使用的交易,如果涉及的索引是部分索引或具有非簡單欄位參考的欄位。 然後,最終索引可以標記為 有效 並準備好使用,並且 CREATE INDEX 命令終止。 但是,即使如此,索引也可能無法立即用於查詢:在最壞的情況下,只要存在早於索引建置開始的交易,就無法使用它。

如果在掃描資料表時出現問題,例如死鎖或唯一索引中的唯一性違規,則 CREATE INDEX 命令將失敗,但會留下一個 無效 索引。 因為此索引可能不完整,所以將忽略此索引以進行查詢目的;但是,它仍然會消耗更新開銷。psql \d 命令會將此類索引報告為 INVALID

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

在這種情況下,建議的恢復方法是刪除索引,然後再次嘗試執行 CREATE INDEX CONCURRENTLY。 (另一種可能性是使用 REINDEX INDEX CONCURRENTLY 重建索引)。

並行建立唯一索引時的另一個注意事項是,當第二次資料表掃描開始時,唯一性約束已經針對其他交易強制執行。 這意味著在索引可用於使用之前,甚至在索引建置最終失敗的情況下,都可能在其他查詢中報告約束違規。 此外,如果第二次掃描確實發生故障,則 無效 索引將繼續在之後強制執行其唯一性約束。

支援並行建立表達式索引和部分索引。 在評估這些表達式時發生的錯誤可能會導致與上述唯一約束違規類似的行為。

一般的索引建立允許在同一個資料表上同時進行其他一般的索引建立,但每次只能在一個資料表上進行一個並行索引建立。在上述任一種情況下,索引建立期間不允許對資料表進行綱要修改。另一個不同之處在於,一般的 CREATE INDEX 指令可以在交易區塊內執行,但 CREATE INDEX CONCURRENTLY 則不行。

目前不支援分割資料表上的索引並行建立。但是,您可以並行地在每個分割區上個別建立索引,然後最終非並行地建立分割索引,以便減少對分割資料表進行寫入鎖定的時間。在這種情況下,建立分割索引僅僅是一種中繼資料操作。

注意事項

請參閱第 11 章,以瞭解何時可以使用索引、何時不使用索引,以及在哪些特定情況下索引可能有用。

目前,只有 B-tree、GiST、GIN 和 BRIN 索引方法支援多鍵值欄位的索引。是否可以有多個鍵值欄位與是否可以將 INCLUDE 欄位新增到索引無關。索引最多可以有 32 個欄位,包括 INCLUDE 欄位。(此限制可以在建置 PostgreSQL 時變更。)目前只有 B-tree 支援唯一索引。

可以為索引的每個欄位指定具有可選參數的運算子類別。運算子類別識別索引要用於該欄位的運算子。例如,四位元整數的 B-tree 索引將使用 int4_ops 類別;此運算子類別包含四位元整數的比較函數。實際上,欄位資料類型的預設運算子類別通常就足夠了。使用運算子類別的主要原因是,對於某些資料類型,可能有多個有意義的排序。例如,我們可能希望按絕對值或實部對複數資料類型進行排序。我們可以透過為資料類型定義兩個運算子類別,然後在建立索引時選擇正確的類別來做到這一點。有關運算子類別的更多資訊,請參閱第 11.10 節第 36.16 節

當在分割資料表上呼叫 CREATE INDEX 時,預設行為是遞迴到所有分割區,以確保它們都具有相符的索引。首先檢查每個分割區,以確定是否已存在等效的索引,如果存在,則該索引將作為分割區索引附加到正在建立的索引,該索引將成為其父索引。如果不存在相符的索引,則將建立一個新的索引並自動附加;每個分割區中新索引的名稱將按照好像指令中未指定索引名稱的方式確定。如果指定了 ONLY 選項,則不會執行遞迴,並且索引將被標記為無效。(ALTER INDEX ... ATTACH PARTITION 會在所有分割區取得相符的索引後,將索引標記為有效。)但是請注意,將來使用 CREATE TABLE ... PARTITION OF 建立的任何分割區將自動具有相符的索引,無論是否指定了 ONLY

對於支援排序掃描的索引方法(目前僅 B-tree),可以指定可選的子句 ASCDESCNULLS FIRST 和/或 NULLS LAST,以修改索引的排序順序。由於可以向前或向後掃描排序的索引,因此建立單欄位 DESC 索引通常沒有用 — 使用常規索引已經可以使用該排序順序。這些選項的價值在於,可以建立多欄位索引,以符合混合排序查詢所請求的排序順序,例如 SELECT ... ORDER BY x ASC, y DESCNULLS 選項在需要支援 空值排序低 行為,而不是預設的 空值排序高,並且查詢依賴索引來避免排序步驟時非常有用。

系統定期收集資料表所有欄位的統計資訊。新建立的非運算式索引可以立即使用這些統計資訊來確定索引的效用。對於新的運算式索引,有必要執行 ANALYZE 或等待自動清理精靈分析資料表,以產生這些索引的統計資訊。

CREATE INDEX 執行時,search_path 暫時變更為 pg_catalog, pg_temp

對於大多數索引方法,建立索引的速度取決於 maintenance_work_mem 的設定。較大的值將減少建立索引所需的時間,只要您不要使其大於實際可用的記憶體量,否則會將機器驅動到交換。

PostgreSQL 可以在利用多個 CPU 的同時建立索引,以便更快地處理資料表列。此功能稱為並行索引建立。對於支援並行建立索引的索引方法(目前僅 B-tree),maintenance_work_mem 指定每個索引建立操作可以使用的最大記憶體量,無論啟動了多少個工作程序。通常,成本模型會自動確定應該請求多少個工作程序(如果有的話)。

在等效的循序索引建立幾乎看不到或沒有任何好處的情況下,並行索引建立可能會受益於增加 maintenance_work_mem。請注意,maintenance_work_mem 可能會影響請求的工作程序數量,因為並行工作程序必須至少擁有 32MB 的總 maintenance_work_mem 預算份額。領導程序還必須剩餘 32MB 份額。增加 max_parallel_maintenance_workers 可能會允許使用更多的工作程序,這將減少建立索引所需的時間,只要索引建立尚未受 I/O 限制。當然,也應該有足夠的 CPU 容量,否則這些容量將閒置。

透過 ALTER TABLE 直接設定 parallel_workers 的值,可以直接控制 CREATE INDEX 針對該表所請求的平行工作者處理序數量。這完全繞過了成本模型,並且防止 maintenance_work_mem 影響請求的平行工作者數量。透過 ALTER TABLEparallel_workers 設定為 0 將在所有情況下停用該表的平行索引建立。

提示

在調整索引建立後,您可能需要重置 parallel_workers。這可以避免意外變更查詢計畫,因為 parallel_workers 會影響所有 平行表掃描。

雖然帶有 CONCURRENTLY 選項的 CREATE INDEX 支援無特殊限制的平行建立,但實際上只有第一次表掃描會以平行方式執行。

使用 DROP INDEX 來移除索引。

如同任何長時間執行的交易,表上的 CREATE INDEX 可能會影響並行 VACUUM 在任何其他表上可以移除哪些元組。

PostgreSQL 的先前版本也具有 R-tree 索引方法。 此方法已被移除,因為它相較於 GiST 方法沒有顯著優勢。 如果指定 USING rtreeCREATE INDEX 會將其解譯為 USING gist,以簡化將舊資料庫轉換為 GiST 的過程。

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

範例

在表 films 中的欄位 title 上建立唯一的 B-tree 索引

CREATE UNIQUE INDEX title_idx ON films (title);

在表 films 中的欄位 title 上建立具有包含欄位 directorrating 的唯一 B-tree 索引

CREATE UNIQUE INDEX title_idx ON films (title) INCLUDE (director, rating);

建立停用重複資料刪除的 B-Tree 索引

CREATE INDEX title_idx ON films (title) WITH (deduplicate_items = off);

在表達式 lower(title) 上建立索引,允許有效的區分大小寫搜尋

CREATE INDEX ON films ((lower(title)));

(在本範例中,我們選擇省略索引名稱,因此系統會選擇一個名稱,通常是 films_lower_idx。)

建立具有非預設定序的索引

CREATE INDEX title_idx_german ON films (title COLLATE "de_DE");

建立具有非預設 NULL 排序的索引

CREATE INDEX title_idx_nulls_low ON films (title NULLS FIRST);

建立具有非預設填滿因子的索引

CREATE UNIQUE INDEX title_idx ON films (title) WITH (fillfactor = 70);

建立一個GIN索引,並且停用快速更新

CREATE INDEX gin_idx ON documents_table USING GIN (locations) WITH (fastupdate = off);

在表 films 的欄位 code 上建立索引,並將索引放置在表空間 indexspace

CREATE INDEX code_idx ON films (code) TABLESPACE indexspace;

在點屬性上建立 GiST 索引,以便我們可以有效地在轉換函式的結果上使用方框運算子

CREATE INDEX pointloc
    ON points USING gist (box(location,location));
SELECT * FROM points
    WHERE box(location,location) && '(0,0),(1,1)'::box;

建立索引而不鎖定對表的寫入

CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity);

相容性

CREATE INDEXPostgreSQL 語言的擴充功能。 SQL 標準中沒有關於索引的規定。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能時的經驗不符或需要進一步澄清的地方,請使用此表格來報告文件問題。