到目前為止我們只討論了「該把哪些欄位放進索引」。有了部分索引(partial index,PostgreSQL 的說法)或篩選索引(filtered index,SQL Server 的說法),你還能指定哪些列被索引。
Oracle 對部分索引有一套獨特的做法,下一節會在本節基礎上說明。
適用情境:帶常數值的常見條件#
部分索引最適合「經常出現、且使用常數值」的 where 條件——例如狀態碼:
SELECT message
FROM messages
WHERE processed = 'N'
AND receiver = ?這類查詢在佇列(queuing)系統中非常常見:抓取特定收件者所有未處理的訊息。已處理的訊息很少被查詢,就算要查,通常也是用主鍵這類更明確的條件。
從完整索引到部分索引#
我們可以用雙欄索引優化它。單就這段查詢而言,欄位順序無關緊要(沒有範圍條件):
CREATE INDEX messages_todo
ON messages (receiver, processed)索引達成了目的,卻包含大量永遠不會被搜尋的列——所有已處理的訊息。拜對數擴展性所賜,查詢依然很快,但浪費了大量磁碟空間。
用部分索引就能把索引限制在未處理的訊息上。語法簡單得出乎意料——就是一個 where 子句:
CREATE INDEX messages_todo
ON messages (receiver)
WHERE processed = 'N'索引只包含滿足該 where 子句的列。在這個例子中,我們甚至可以移除
PROCESSED欄位——因為它反正永遠是'N'。索引因此在兩個維度上同時縮小:
- 垂直:包含的列變少。
- 水平:移除了一個欄位。
對佇列而言,這甚至意味著即使資料表無限成長,索引大小仍維持不變——索引裡放的不是所有訊息,只有未處理的那些。
限制#
部分索引的 where 子句可以任意複雜,唯一的根本限制與函式有關:
- 只能使用具決定性的函式(如同索引定義中的其他地方)。
- SQL Server 的規則更嚴格:索引述詞中既不允許函式,也不允許
OR運算子。
只要查詢中出現該 where 子句,資料庫就能使用這個部分索引。
SELECT message FROM messages WHERE processed = 'N';