到目前為止我們只討論了「該把哪些欄位放進索引」。有了部分索引(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';