多列索引
一個(gè)索引可以定義在表的多個(gè)列上。例如,我們有這樣一個(gè)表:
CREATE TABLE test2 (
major int,
minor int,
name varchar
);
(即將我們的/dev
目錄保存在數(shù)據(jù)庫中)而且我們經(jīng)常會(huì)做如下形式的查詢:
SELECT name FROM test2 WHERE major = constant AND minor = constant;
那么我們可以在major
和minor
上定義一個(gè)索引:
CREATE INDEX test2_mm_idx ON test2 (major, minor);
目前,只有 B-tree、GiST、GIN 和 BRIN 索引類型支持多列索引,最多可以指定 32 個(gè)列(該限制可以在源代碼文件pg_config_manual.h
中修改,但是修改后需要重新編譯本數(shù)據(jù)庫)。
多列B-tree索引可以用于條件中涉及到任意索引列子集的查詢,但是當(dāng)先導(dǎo)列(即最左邊的那些列)上有約束條件時(shí)索引最為有效。確切的規(guī)則是:在先導(dǎo)列上的等值約束,加上第一個(gè)無等值約束的列上的不等值約束,將被用于限制索引被掃描的部分。在這些列右邊的列上的約束將在索引中被檢查,這樣它們適當(dāng)節(jié)約了對表的訪問,但它們并未減小索引被掃描的部分。例如,在
(a, b, c)
上有一個(gè)索引并且給定一個(gè)查詢條件WHERE a = 5 AND b >= 42 AND c < 77
,對索引的掃描將從第一個(gè)具有a
= 5 和b
= 42 的項(xiàng)開始向上進(jìn)行,直到最后一個(gè)具有a
= 5 的項(xiàng)。在掃描過程中,具有c
>= 77 的索引項(xiàng)將被跳過,但是它們還是會(huì)被掃描到。這個(gè)索引在原則上可以被用于在b
和/或c
上有約束而在a
上沒有約束的查詢,但是整個(gè)索引都不得不被掃描,因此在大部分情況下規(guī)劃器寧可使用一個(gè)順序的表掃描來替代索引。多列GiST索引可以用于條件中涉及到任意索引列子集的查詢。在其余列上的條件將限制由索引返回的項(xiàng),但是第一列上的條件是決定索引上掃描量的最重要因素。當(dāng)?shù)谝涣兄芯哂泻苌俚目蓞^(qū)分值時(shí),一個(gè) GiST 索引將會(huì)相對比較低效,即便在其他列上有很多可區(qū)分值。
多列GIN索引可以用于條件中涉及到任意索引列的子集的查詢。與 B-tree 和 GiST 不同,GIN 的搜索效率與查詢條件中使用哪些索引列無關(guān)。
多列BRIN索引可以被用于涉及該索引被索引列的任意子集的查詢條件。和 GIN 相似且不同于 B-樹或者 GiST,索引搜索效率與查詢條件使用哪個(gè)索引列無關(guān)。在單個(gè)表上使用多個(gè) BRIN 索引來取代一個(gè)多列 BRIN 索引的唯一原因是為了使用不同的
pages_per_range
存儲(chǔ)參數(shù)。
當(dāng)然,要使索引起作用,查詢條件中的列必須要使用適合于索引類型的操作符,使用其他操作符的子句將不會(huì)被考慮使用索引。
多列索引應(yīng)該較少地使用。在絕大多數(shù)情況下,單列索引就足夠了且能節(jié)約時(shí)間和空間。具有超過三個(gè)列的索引不太有用,除非該表的使用是極端程式化的。