Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql Postgres在查询计划中使用了错误的索引_Postgresql_Indexing_Amazon Rds_Sql Execution Plan - Fatal编程技术网

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

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 我已经尝试过以

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