---
# System prepended metadata

title: Partial Indexes

---

# 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
