# PostgreSQL 的 Partial Indexes ## 說明 部分索引(partial index)是在資料表的子集上建構的索引;子集由條件表示式(所以稱作為部分索引)定義。索引僅包含滿足條件的資料列 (row)。 使用部分索引的一個主要原因是避免索引常見值。由於搜尋公共值(common value)(佔所有資料表的某個比例以上的值)的查詢無論如何都不會使用索引,因此根本不應該將這些資料列保留在索引中。這可以減少索引的大小,將加速那些使用索引的查詢。它還將加速許多資料表的更新操作,因為索引不需要在所有情況下都更新。 [文件](https://docs.postgresql.tw/the-sql-language/index/partial-indexes) 只有當系統能夠識別出查詢的 WHERE 條件在數學上暗示索引的條件時,才能在查詢中使用部分索引。 ## Partial Unique Index 使用情境 [文件範例 11.3](https://docs.postgresql.tw/the-sql-language/index/partial-indexes#fan-li-11.3.-she-ding-bu-fen-wei-yi-suo-yin) [Rails](https://api.rubyonrails.org/v7.1.3/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_index): Note: Partial indexes are only supported for PostgreSQL and SQLite. ```ruby class AddPartialIndexToTests < ActiveRecord::Migration[6.0] def change add_index :tests, [:subject :target], unique: true, where: 'success' end end ``` 搭配 model 上的 [validates](https://api.rubyonrails.org/v7.1.3/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of) 使用 ```ruby class Test < ApplicationRecord validates :subject, uniqueness: { scope: :target, conditions: -> { where('success') } } end ``` ## Do Not Use Partial Indexes as a Substitute for Partitioning 分類的情況,建議用單一索引 https://www.postgresql.org/docs/current/indexes-partial.html#INDEXES-PARTIAL ## 結論 Partial Index 適合用在 1. 條件相對固定的情況下,例如系統如果有用軟刪除,又希望依靠 unique index 避免 race condition 造成產生多筆相同資料的情境 2. 查詢範圍永遠是全部資料集的 10%,這樣建立 partial index 就可以精煉為 10% 的大小 ([要快就要少](https://hackmd.io/@tim-tf-chen/rJoqtJYUj)) ## 資料來源: https://www.postgresql.org/docs/current/indexes-partial.html#INDEXES-PARTIAL https://docs.postgresql.tw/the-sql-language/index/partial-indexes https://www.ironin.it/blog/partial-unique-indexes-in-postgresql-and-rails.html