Postgres在查询计划中使用错误的索引

时间:2015-02-26 11:00:08

标签: postgresql indexing amazon-rds sql-execution-plan

下面我有两个几乎相同的查询,只有限制不同。 然而,查询计划和执行时间完全不同。第一个查询比第二个查询慢+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"

1 个答案:

答案 0 :(得分:1)

此查询开始变慢。它应该不到1秒。

您的第一个示例首先使用edited_date索引对数据进行排序,然后对已排序的数据进行过滤。

您的第二个示例,对数据进行排序(似乎没有索引),然后应用索引扫描来获取实际行。这两种方法都很糟糕。

什么可能加快速度,是owner_id和edited_date的复合索引,如果经常使用这种查询,这将是有意义的。该索引也将取代其他索引之一,甚至可能两者都取代。