我的USERS表(15M行)包含last_name(Varchar)和status(整型)列.姓氏是一些随机姓氏,状态是:

enum status: { active: 0, archived: 1, blocked: 2, inactive: 3, part_active: 4, disabled: 5 }

我想在这上面加上复合指数.我使用的是Rails,所以基本上是这样的:

add_index :users, [:last_name, :status]

我用简单的查询对其进行了测试:

 User.where(status: 'active', last_name: 'Anderson').explain(:analyze)

作为计划者的结果,我得到了:

Bitmap Heap Scan on users  (cost=4.68..102.86 rows=25 width=108) (actual time=0.559..1.446 rows=489 loops=1)
   Recheck Cond: (((last_name)::text = 'Anderson'::text) AND (status = 0))
   Heap Blocks: exact=484
   ->  Bitmap Index Scan on index_users_on_last_name_and_status  (cost=0.00..4.68 rows=25 width=0) (actual time=0.091..0.092 rows=489 loops=1)
         Index Cond: (((last_name)::text = 'Anderson'::text) AND (status = 0))
 Planning Time: 0.133 ms
 Execution Time: 1.535 ms

令我惊讶的是,当我更改索引中列的顺序时,我得到了不同的(更简单的)查询计划:

add_index :users, [:status, :last_name]

它的结果是这样一个计划:

 Index Scan using index_users_on_status_and_last_name on users  (cost=0.43..103.41 rows=25 width=108) (actual time=0.065..0.755 rows=489 loops=1)
   Index Cond: ((status = 0) AND ((last_name)::text = 'Anderson'::text))
 Planning Time: 0.152 ms
 Execution Time: 0.813 ms

我的PostgreSQL版本是13.

为什么我在计划器中因为更改了订单而得到了不同的结果?据我所知,当我只使用相等匹配器时,数据的基数/ Select 性应该不会影响,它应该只影响<>等匹配器,就像我判断的示例here一样.

推荐答案

差异可能基于每个属性与表中行的物理顺序之间的相关性.有关每个属性,请参见pg_stats.relationship.当索引中前导列的相关性较低时,规划器假设它将跳转到表的随机部分,从而导致较差的IO模式.使用位图扫描可以部分改善这一点,因此低相关性鼓励使用位图扫描而不是普通索引扫描.

据我所知,当我只使用等式匹配器时,数据的基数/ Select 性应该不会受到影响

你可以看到两个计划都有相同的基数估计(这个估计是错误的,这比计划 Select 的差异更令我担心. 但基数并不是成本估算中唯一的因素.

Postgresql相关问答推荐

优化PostgreSQL查询以将用户插入数据库

mosquito-go-auth with postgres authorization error

如何在Postgres中对分区表使用Hibernate验证?

Postgres 查询指向国外数据工作者的分区表比直接查询 fdw 慢很多倍

使用 GDB 调试器调试 AGE 代码的过程

错误:分区表的唯一约束必须包括所有分区列

为什么我使用 VBA 只能从 postgres 获得 10 行?

无法从 docker-compose 上的其他服务解析 postgres 主机名

PostgreSQL - 如何获得前一个月和一周的价值?

PostgreSQL:please specify covering index name是什么意思

如何从元组列表中 Select 与多列匹配的行?

PostgreSQL 在 mySQL 中的 date_trunc

PostgreSQL 中的 JSON 外键

在查询中的复合外键/主键列上连接表

Sidekiq - 无法在 5.000 秒内获得数据库连接

Django:按月查询组

psql 致命角色不存在

从长时间的postgres转换日期

try 为 ror 应用程序设置 postgres,出现错误 - fe_sendauth:no password supplied

PostgreSQL 字符串(255) 限制 - Rails、Ruby 和 Heroku