Postgresql Postgres在查询计划中使用了错误的索引
下面我有两个几乎相同的查询,只是限制不同。 然而,查询计划和执行时间是完全不同的。第一个查询比第二个查询慢+300倍 该问题仅在少数所有者ID中出现。拥有多条路线(+1000)的所有者,最近没有一条路线经过编辑。 表路由包含2806976行。示例中的所有者有4510条路由 数据库托管在服务器上的Amazon RDS上,该服务器具有34.2 GiB内存、4vCPU和配置的IOPS(实例类型db.m2.2xlarge) 如何确保Postgres使用索引路由\u I\u所有者\u id 我已经尝试过以下方法:Postgresql Postgres在查询计划中使用了错误的索引,postgresql,indexing,amazon-rds,sql-execution-plan,Postgresql,Indexing,Amazon Rds,Sql Execution Plan,下面我有两个几乎相同的查询,只是限制不同。 然而,查询计划和执行时间是完全不同的。第一个查询比第二个查询慢+300倍 该问题仅在少数所有者ID中出现。拥有多条路线(+1000)的所有者,最近没有一条路线经过编辑。 表路由包含2806976行。示例中的所有者有4510条路由 数据库托管在服务器上的Amazon RDS上,该服务器具有34.2 GiB内存、4vCPU和配置的IOPS(实例类型db.m2.2xlarge) 如何确保Postgres使用索引路由\u I\u所有者\u id 我已经尝试过以
- 增加已编辑日期和所有者id的统计信息
ALTER TABLE route ALTER COLUMN owner_id SET STATISTICS 1000; ALTER TABLE route ALTER COLUMN edited_date SET STATISTICS 1000;
- 整个数据库的真空分析
CREATE INDEX route_i_owner_id_edited_date
ON public.route
USING btree
(owner_id, edited_date DESC);
EXPLAIN ANALYZE SELECT
id
FROM
route
WHERE
owner_id = 39127
ORDER BY
edited_date DESC
LIMIT
5
"Limit (cost=0.43..16.99 rows=5 width=12) (actual time=0.028..0.050 rows=5 loops=1)"
" -> Index Scan using route_i_owner_id_edited_date on route (cost=0.43..15746.74 rows=4753 width=12) (actual time=0.025..0.039 rows=5 loops=1)"
" Index Cond: (owner_id = 39127)"
"Total runtime: 0.086 ms"
这个查询一开始就很慢。时间应少于1秒 第一个示例使用已编辑的日期索引对数据进行排序,然后过滤排序后的数据 第二个示例对数据进行排序(似乎没有索引),然后应用索引扫描来获取实际行。这两种方法似乎都不好
可能会加快速度的是,拥有者id和编辑日期的复合索引,如果经常使用这种查询,这将是有意义的。此索引还将替换其他索引中的一个,甚至可能两者都替换。第二个查询相当快,38毫秒。在复合索引中,我应该首先放置什么?Owner\u id或edited\u date?@pieter您放在第一位的列对于单列查询来说是最有效的,因此如果您经常单独查询Owner\u id,这应该是第一位。如果您经常只排序和限制(例如,order by edited_date limit 5,不带where子句),那么将其放在第一位或创建第二个索引(仅包含edited_date)可能是有意义的。您需要测试查询,看看它有多大的不同。您是否在表上尝试了
REINDEX
?PostgreSQL还应该在必要时组合使用这两个索引:“幸运的是,PostgreSQL能够组合多个索引(包括同一索引的多次使用)处理单索引扫描无法实现的情况。”(来自文档)。我仍然会说原始索引route\u I\u edited\u date
有问题。我尝试了重新索引,但没有成功。复合索引解决了我的问题@Simo Kivistö如果你发布索引定义,可能会有另一种解释来解释这种行为。正如@SimoKivistö指出的,postgres可以使用多个索引。这可能是由于编辑的日期索引需要很长时间才能反转,再加上排序操作的内存限制较低,这可能会迫使它使用基于磁盘的排序。顺便说一句:如果ORDER BY xxx limit yyy
表现不好(通常是这样;优化器在外部查询中没有足够的自由度),一个常见的技巧是将(按xxx排序)上的行()重写为rn。。。rn在哪里
CREATE INDEX route_i_owner_id_edited_date
ON public.route
USING btree
(owner_id, edited_date DESC);
EXPLAIN ANALYZE SELECT
id
FROM
route
WHERE
owner_id = 39127
ORDER BY
edited_date DESC
LIMIT
5
"Limit (cost=0.43..16.99 rows=5 width=12) (actual time=0.028..0.050 rows=5 loops=1)"
" -> Index Scan using route_i_owner_id_edited_date on route (cost=0.43..15746.74 rows=4753 width=12) (actual time=0.025..0.039 rows=5 loops=1)"
" Index Cond: (owner_id = 39127)"
"Total runtime: 0.086 ms"