多列索引与单独索引与部分索引
Multi-column index vs seperate indexes vs partial indexes
今天在开发我的 Rails 应用程序时,我注意到偏执狂 gem 说应该更新索引以添加 deleted_at IS NOT NULL
作为创建索引的位置(github link).但我突然想到,当我想要 with_deleted 时,倒置条件不会从索引中受益。
这让我想知道...
我知道这有点迟钝,因为答案显然是 "it depends on what you need",但我想了解我的 Web 应用程序中多列索引与单独索引与部分索引之间的区别PostgreSQL.
基本上,我有 2 个要查询的字段:p_id 和 deleted_at。大多数时候我查询 WHERE p_id=1 AND deleted_at IS NOT NULL
- 但有时我只查询 WHERE p_id=1
。很少,我会WHERE p_id=1 AND deleted_at=1/1/2017
.
所以,我过得更好吗:
- 在 p_id 上有一个索引,在 deleted_at 上有一个单独的索引?
- 在 p_id 上有索引但添加 'where deleted_at IS NOT NULL'?
- 在 p_id 和 deleted_at 上有一个组合索引?
注意:也许我应该提到 p_id 当前是对 p.id 的外键引用。这让我想起,在 Postgres 中,外键是否也有索引(或者它们是否从外键约束中获得索引 - 我读过关于此的相互矛盾的答案)?
答案取决于
- 您使用这些查询的频率以及允许使用多长时间 运行
- 如果查询速度足够重要,可以容忍缓慢的数据更改。
三个子句的完美索引是:
WHERE p_id=1 AND deleted_at IS NOT NULL
CREATE INDEX ON mytable (p_id) WHERE deleted_at IS NOT NULL;
WHERE p_id=1 AND deleted_at=1/1/2017
CREATE INDEX ON mytable (p_id, deleted_at);
WHERE p_id=1
CREATE INDEX ON mytable (p_id);
为2.创建的索引也可以用于3.,所以如果你需要尽可能加快第二个查询,稍微大一点的索引不打扰你,只从2创建索引. 对于两个查询。
然而,来自 3. 的索引也会加速 2. 中的查询,只是不是尽可能快,所以如果你可以忍受 2. 中的查询性能稍微差一点,并希望索引为3.中的查询尽可能小而高效,只创建3.中的索引
我会不会从 2. 和 3. 创建两个索引;你应该选择最适合你的。
1.的情况不同,因为该索引只能用于第一个查询。仅当您想尽可能加快该查询时才创建该索引,并且 table 上的数据修改是否花费更长时间并不重要,因为必须维护一个额外的索引。
在 1. 中创建索引的另一个迹象是只有一小部分行满足 deleted_at IS NOT NULL
。如果不是,则 1. 中的索引与 3. 中的索引相比没有太大优势,您应该创建后者。
在两个列上有两个单独的索引可能不是最好的选择——它们只能与位图索引扫描结合使用,而且 PostgreSQL 很可能只选择使用其中一个索引(取决于分布,但可能是p_id
上的那个),另一个没用。
今天在开发我的 Rails 应用程序时,我注意到偏执狂 gem 说应该更新索引以添加 deleted_at IS NOT NULL
作为创建索引的位置(github link).但我突然想到,当我想要 with_deleted 时,倒置条件不会从索引中受益。
这让我想知道...
我知道这有点迟钝,因为答案显然是 "it depends on what you need",但我想了解我的 Web 应用程序中多列索引与单独索引与部分索引之间的区别PostgreSQL.
基本上,我有 2 个要查询的字段:p_id 和 deleted_at。大多数时候我查询 WHERE p_id=1 AND deleted_at IS NOT NULL
- 但有时我只查询 WHERE p_id=1
。很少,我会WHERE p_id=1 AND deleted_at=1/1/2017
.
所以,我过得更好吗:
- 在 p_id 上有一个索引,在 deleted_at 上有一个单独的索引?
- 在 p_id 上有索引但添加 'where deleted_at IS NOT NULL'?
- 在 p_id 和 deleted_at 上有一个组合索引?
注意:也许我应该提到 p_id 当前是对 p.id 的外键引用。这让我想起,在 Postgres 中,外键是否也有索引(或者它们是否从外键约束中获得索引 - 我读过关于此的相互矛盾的答案)?
答案取决于
- 您使用这些查询的频率以及允许使用多长时间 运行
- 如果查询速度足够重要,可以容忍缓慢的数据更改。
三个子句的完美索引是:
WHERE p_id=1 AND deleted_at IS NOT NULL
CREATE INDEX ON mytable (p_id) WHERE deleted_at IS NOT NULL;
WHERE p_id=1 AND deleted_at=1/1/2017
CREATE INDEX ON mytable (p_id, deleted_at);
WHERE p_id=1
CREATE INDEX ON mytable (p_id);
为2.创建的索引也可以用于3.,所以如果你需要尽可能加快第二个查询,稍微大一点的索引不打扰你,只从2创建索引. 对于两个查询。
然而,来自 3. 的索引也会加速 2. 中的查询,只是不是尽可能快,所以如果你可以忍受 2. 中的查询性能稍微差一点,并希望索引为3.中的查询尽可能小而高效,只创建3.中的索引
我会不会从 2. 和 3. 创建两个索引;你应该选择最适合你的。
1.的情况不同,因为该索引只能用于第一个查询。仅当您想尽可能加快该查询时才创建该索引,并且 table 上的数据修改是否花费更长时间并不重要,因为必须维护一个额外的索引。
在 1. 中创建索引的另一个迹象是只有一小部分行满足 deleted_at IS NOT NULL
。如果不是,则 1. 中的索引与 3. 中的索引相比没有太大优势,您应该创建后者。
在两个列上有两个单独的索引可能不是最好的选择——它们只能与位图索引扫描结合使用,而且 PostgreSQL 很可能只选择使用其中一个索引(取决于分布,但可能是p_id
上的那个),另一个没用。