Postgres 在枚举类型上使用部分索引来满足相等条件而不是不相等条件
Postgres using partial index on enum type for equality condition but not for inequality
使用 PostgreSQL 9.6.9,我有:
- 自定义 SQL 枚举类型,具有 3 个级别,用于某些列
table xy.
- 在 table xy 上此枚举的最高级别(级别 3)的复合部分索引。
- 大量虚拟数据(超过 200000 行)
并在控制台中使用 EXPLAIN ANALYSE
,我看到:
SELECT ... FROM xy WHERE ... AND custom_type = 'level3' <--- Index Scan used
但是:
SELECT ... FROM xy WHERE ... AND custom_type > 'level2' <--- Index Scan NOT used
查询完全相同,除了 inequality/equality 条件。
数据库规划师是不是看不到level2以上只能有level3才能使用部分索引?
为什么 Postgres 没有适当地优化它...这似乎是一些简单的逻辑问题。
一般
Postgres 仅在估计整体速度更快时才使用索引(或位图索引)扫描。不等式条件通常比等式条件 returns(多)行。因此,如果 table 统计数据和成本设置表明这可能更快,查询计划器可能会切换到顺序扫描。当从 table 中提取 小 百分比的行时,使用索引会增加开销并且通常只会提高性能。大约 5% 或更少,因细节而异。
您确定 table 统计数据是最新的吗?你 运行 ANALYZE
在 table 上了吗?参见:
- Keep PostgreSQL from sometimes choosing a bad query plan
要测试是否可以使用索引,请在测试会话中禁用顺序扫描(仅用于调试!):
SET enable_seqscan = OFF;
然后 运行 再 EXPLAIN ANALYZE
。
部分索引
如果 WHERE
条件在查询中几乎 完全 满足,Postgres 只考虑部分索引。没有尝试分析表达式的高级逻辑(因为这可能很快就会失控并增加大多数不从部分索引中获利的查询的开销)。
如果您有条件 WHERE custom_type = 'level3'
的部分索引,则甚至不会考虑条件 WHERE custom_type > 'level2'
的查询。简单的解决方案是将部分索引的条件添加到您的查询中(冗余)。喜欢:
SELECT ... FROM xy WHERE ... AND custom_type > 'level2'
AND custom_type = 'level3'; -- redundant, but makes Postgres consider partial index
自作聪明时要小心:如果以后扩展 enum
类型,查询可能会中断。
相关:
- PostgreSQL does not use a partial index
- Optimize performance for queries on recent rows of a large table
索引和统计数据
注意两点:
对于涉及函数表达式的部分索引,有单独的每列统计信息,但不只是简单的列引用。
创建索引不会自动触发基础 table(或其本身)上的 ANALYZE
。但是像行数这样的基本统计信息会在 pg_class
.
中更新
- Kaminari is slow with COUNT(*) on a huge table in Postgres
- PostgreSQL partial index unused when created on a table with existing data
- Inconsistent statistics on jsonb column with btree index
- GIN index not used when adding order clause
- Optimizing slow performance of simple SELECT query
使用 PostgreSQL 9.6.9,我有:
- 自定义 SQL 枚举类型,具有 3 个级别,用于某些列 table xy.
- 在 table xy 上此枚举的最高级别(级别 3)的复合部分索引。
- 大量虚拟数据(超过 200000 行)
并在控制台中使用 EXPLAIN ANALYSE
,我看到:
SELECT ... FROM xy WHERE ... AND custom_type = 'level3' <--- Index Scan used
但是:
SELECT ... FROM xy WHERE ... AND custom_type > 'level2' <--- Index Scan NOT used
查询完全相同,除了 inequality/equality 条件。
数据库规划师是不是看不到level2以上只能有level3才能使用部分索引?
为什么 Postgres 没有适当地优化它...这似乎是一些简单的逻辑问题。
一般
Postgres 仅在估计整体速度更快时才使用索引(或位图索引)扫描。不等式条件通常比等式条件 returns(多)行。因此,如果 table 统计数据和成本设置表明这可能更快,查询计划器可能会切换到顺序扫描。当从 table 中提取 小 百分比的行时,使用索引会增加开销并且通常只会提高性能。大约 5% 或更少,因细节而异。
您确定 table 统计数据是最新的吗?你 运行 ANALYZE
在 table 上了吗?参见:
- Keep PostgreSQL from sometimes choosing a bad query plan
要测试是否可以使用索引,请在测试会话中禁用顺序扫描(仅用于调试!):
SET enable_seqscan = OFF;
然后 运行 再 EXPLAIN ANALYZE
。
部分索引
如果 WHERE
条件在查询中几乎 完全 满足,Postgres 只考虑部分索引。没有尝试分析表达式的高级逻辑(因为这可能很快就会失控并增加大多数不从部分索引中获利的查询的开销)。
如果您有条件 WHERE custom_type = 'level3'
的部分索引,则甚至不会考虑条件 WHERE custom_type > 'level2'
的查询。简单的解决方案是将部分索引的条件添加到您的查询中(冗余)。喜欢:
SELECT ... FROM xy WHERE ... AND custom_type > 'level2'
AND custom_type = 'level3'; -- redundant, but makes Postgres consider partial index
自作聪明时要小心:如果以后扩展 enum
类型,查询可能会中断。
相关:
- PostgreSQL does not use a partial index
- Optimize performance for queries on recent rows of a large table
索引和统计数据
注意两点:
对于涉及函数表达式的部分索引,有单独的每列统计信息,但不只是简单的列引用。
创建索引不会自动触发基础 table(或其本身)上的 ANALYZE
。但是像行数这样的基本统计信息会在 pg_class
.
- Kaminari is slow with COUNT(*) on a huge table in Postgres
- PostgreSQL partial index unused when created on a table with existing data
- Inconsistent statistics on jsonb column with btree index
- GIN index not used when adding order clause
- Optimizing slow performance of simple SELECT query