下面我有两个几乎相同的查询,只有限制不同。 然而,查询计划和执行时间完全不同。第一个查询比第二个查询慢+300倍。
只有少量owner_ids才会出现此问题。拥有许多路线(+1000)的业主,最近都没有编辑过。 表路由包含2,806,976行。示例中的所有者有4,510条路线。
数据库托管在具有34.2 GiB内存,4vCPU和预配置IOPS(实例类型为db.m2.2xlarge)的服务器上的Amazon RDS上。
EXPLAIN ANALYZE SELECT
id
FROM
route
WHERE
owner_id = 39127
ORDER BY
edited_date DESC
LIMIT
5
Query plan:
"Limit (cost=0.43..5648.85 rows=5 width=12) (actual time=1.046..12949.436 rows=5 loops=1)"
" -> Index Scan Backward using route_i_edited_date on route (cost=0.43..5368257.28 rows=4752 width=12) (actual time=1.042..12949.418 rows=5 loops=1)"
" Filter: (owner_id = 39127)"
" Rows Removed by Filter: 2351712"
"Total runtime: 12949.483 ms"
EXPLAIN ANALYZE SELECT
id
FROM
route
WHERE
owner_id = 39127
ORDER BY
edited_date DESC
LIMIT
15
Query plan:
"Limit (cost=13198.79..13198.83 rows=15 width=12) (actual time=37.781..37.821 rows=15 loops=1)"
" -> Sort (cost=13198.79..13210.67 rows=4752 width=12) (actual time=37.778..37.790 rows=15 loops=1)"
" Sort Key: edited_date"
" Sort Method: top-N heapsort Memory: 25kB"
" -> Index Scan using route_i_owner_id on route (cost=0.43..13082.20 rows=4752 width=12) (actual time=0.039..32.425 rows=4510 loops=1)"
" Index Cond: (owner_id = 39127)"
"Total runtime: 37.870 ms"
如何确保Postgres使用索引route_i_owner_id。
我已经尝试过以下事项:
增加edited_date和owner_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"
答案 0 :(得分:1)
此查询开始变慢。它应该不到1秒。
您的第一个示例首先使用edited_date索引对数据进行排序,然后对已排序的数据进行过滤。
您的第二个示例,对数据进行排序(似乎没有索引),然后应用索引扫描来获取实际行。这两种方法都很糟糕。
什么可能加快速度,是owner_id和edited_date的复合索引,如果经常使用这种查询,这将是有意义的。该索引也将取代其他索引之一,甚至可能两者都取代。