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

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

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

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

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

可能会加快速度的是 owner_id 和 edited_date 的复合索引,如果经常使用这种查询,这将很有意义。该索引还将替换其他索引之一,甚至可能同时替换两者。

关于postgresql - Postgres 在查询计划中使用了错误的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28740639/

相关文章:

sql - 在 PostgreSQL 中使用关联数组进行批量更新

mysql - 使用具有低基数的索引是否有意义?

mysql - 在 AWS RDS 实例之间移动数据

postgresql - 在 postgresql 中按 boxcolumn 排序查询

java - 如何使用 java 提取 Postgres 时间戳字段?

postgresql - 为什么 PostgreSQL 中止这个可序列化的计划

mysql - 如何/在何处从 MySql 删除/编辑索引以防止重复行

c++ - 查找 wxMenu 的选定单选项

mysql - 如何在 php 和 mysql 中修复 mysql 大写查询

amazon-web-services - 让 Sequelize.js 库在 Amazon Lambda 上工作