1

如果您查询日期范围和另一件事,那么将日期列作为索引中的前沿是一件坏事吗?

我正在使用 PostgreSQL,但假设这适用于所有 B 树索引。

假设我查询了创建日期为 2013-01-02 或更晚且状态为活动的记录。我对 B 树索引如何组织日期很模糊,但这就是我的想象。如果索引打开(创建,状态),它的结构大致如下:

created       status
------------------------
2013-01-01    Active
2013-01-01    Inactive
2013-01-02    Active    <-- This record is selected
2013-01-02    Inactive
2013-01-03    Active    <-- This non-adjacent record is selected (SLOW)
2013-01-03    Inactive

如果索引打开(状态,已创建):

status      created
------------------------
Active      2013-01-01
Active      2013-01-02    <-- This record is selected
Active      2013-01-03    <-- This adjacent record is selected (FAST)
Inactive    2013-01-01
Inactive    2013-01-02
Inactive    2013-01-03

所以在我看来,如果您使用日期作为前沿并查询这些日期的范围,那么您想要的记录将在索引中分散,导致性能下降。日期时间更糟。

4

2 回答 2

3

我认为你最好的方法是使用表达式索引。听起来您将主要运行以下查询:

select * from my_table where status='Active' and created_date > whatever

如果是这种情况,您可能会通过在创建日期创建索引并按状态过滤来看到最佳性能:

CREATE INDEX active_status_created_idx on my_table(created) WHERE status='Active'

这将导致可用于包括WHERE status='Active'子句在内的任何查询的索引显着减小。

看:

于 2013-06-13T17:57:52.453 回答
2

就我所读到的而言,你的假设都是正确的。您应该根据最常进行的查询类型来选择索引。

如果您正在做很多where status = ? order by created limit 10or order by status, created limit 10,那么(status, created)通常按顺序排列索引。

如果你做了很多where created = ? order by status limit 10or order by created, status limit 10,那么你通常会想要一个索引来(created, status)代替。

请注意,Postgres 也允许对索引进行显式排序,例如(created, status desc). 文档对为什么有时需要这样做进行了冗长的讨论。(我不记得确切的位置,但我相信你已经发现它已经考虑到你如何表达你的问题了。)

还要注意每种情况下的限制。ordering 子句索引的使用取决于您要检索的行数。获取足够多的行,Postgres 可能更愿意完全忽略您精心创建的索引,而是通过其他方式检索前 n 种行。

最后,请注意 Postgres 在管理单个列上的多个独立索引方面非常出色,尤其是在最近的版本中。事实上,手册中与索引相关的章节中有一个讨论正是讨论了这一点。

如果您有一个索引 on(created)和另一个 on (status),它将知道对查询进行位图索引扫描,例如where status = ? and/or created = ?当两者都具有足够的选择性时。同样,它会知道简单地将索引(created)用于查询,例如where status = ? order by created limit 10,并过滤掉status没有正确值的行。

于 2013-06-13T18:12:39.303 回答