为什么postgresql查询的这种独特/内部连接/顺序如此缓慢?
完成此查询大约需要4秒钟:为什么postgresql查询的这种独特/内部连接/顺序如此缓慢?,sql,performance,postgresql,Sql,Performance,Postgresql,完成此查询大约需要4秒钟: SELECT DISTINCT "resources_resource"."id", "resources_resource"."heading", "resources_resource"."name", "resources_resource"."old_name", "resources_resource"."clean
SELECT DISTINCT "resources_resource"."id",
"resources_resource"."heading",
"resources_resource"."name",
"resources_resource"."old_name",
"resources_resource"."clean_name",
"resources_resource"."sort_name",
"resources_resource"."see_also_id",
"resources_resource"."referenced_passages",
"resources_resource"."resource_type",
"resources_resource"."ord",
"resources_resource"."content",
"resources_resource"."thumb",
"resources_resource"."resource_origin"
FROM "resources_resource"
INNER JOIN "resources_passageresource" ON ("resources_resource"."id" = "resources_passageresource"."resource_id")
WHERE "resources_passageresource"."start_ref" >= 66001001
ORDER BY "resources_resource"."ord" ASC, "resources_resource"."sort_name" ASC LIMIT 5
根据大众要求,解释和分析:
Limit (cost=1125.50..1125.68 rows=5 width=803) (actual time=4434.076..4434.557 rows=5 loops=1)
-> Unique (cost=1125.50..1136.91 rows=326 width=803) (actual time=4434.076..4434.557 rows=5 loops=1)
-> Sort (cost=1125.50..1126.32 rows=326 width=803) (actual time=4434.075..4434.075 rows=6 loops=1)
Sort Key: resources_resource.ord, resources_resource.sort_name, resources_resource.id, resources_resource.heading, resources_resource.name, resources_resource.old_name, resources_resource.clean_name, resources_resource.see_also_id, resources_resource.referenced_passages, resources_resource.resource_type, resources_resource.content, resources_resource.thumb, resources_resource.resource_origin
Sort Method: quicksort Memory: 424kB
-> Hash Join (cost=697.00..1111.89 rows=326 width=803) (actual time=3.453..41.429 rows=424 loops=1)
Hash Cond: (resources_passageresource.resource_id = resources_resource.id)
-> Bitmap Heap Scan on resources_passageresource (cost=10.78..190.19 rows=326 width=4) (actual time=0.107..0.401 rows=424 loops=1)
Recheck Cond: (start_ref >= 66001001)
-> Bitmap Index Scan on resources_passageresource_start_ref (cost=0.00..10.70 rows=326 width=0) (actual time=0.086..0.086 rows=424 loops=1)
Index Cond: (start_ref >= 66001001)
-> Hash (cost=431.32..431.32 rows=2232 width=803) (actual time=3.228..3.228 rows=2232 loops=1)
Buckets: 1024 Batches: 2 Memory Usage: 947kB
-> Seq Scan on resources_resource (cost=0.00..431.32 rows=2232 width=803) (actual time=0.002..1.621 rows=2232 loops=1)
Total runtime: 4435.460 ms
这是ORM生成的SQL。我可以使用SQL,但我绝对不精通,这里的解释输出让我感到困惑。这个问题会把我拖下水吗
更新:@Ybakos发现的订单造成了麻烦。完全删除ORDER\u BY
子句会有所帮助,但查询仍然需要800毫秒。下面是解释分析,sansORDER\u BY
:
HashAggregate (cost=1122.49..1125.75 rows=326 width=803) (actual time=787.519..787.559 rows=104 loops=1)
-> Hash Join (cost=697.00..1111.89 rows=326 width=803) (actual time=3.381..7.312 rows=424 loops=1)
Hash Cond: (resources_passageresource.resource_id = resources_resource.id)
-> Bitmap Heap Scan on resources_passageresource (cost=10.78..190.19 rows=326 width=4) (actual time=0.095..0.686 rows=424 loops=1)
Recheck Cond: (start_ref >= 66001001)
-> Bitmap Index Scan on resources_passageresource_start_ref (cost=0.00..10.70 rows=326 width=0) (actual time=0.079..0.079 rows=424 loops=1)
Index Cond: (start_ref >= 66001001)
-> Hash (cost=431.32..431.32 rows=2232 width=803) (actual time=3.173..3.173 rows=2232 loops=1)
Buckets: 1024 Batches: 2 Memory Usage: 947kB
-> Seq Scan on resources_resource (cost=0.00..431.32 rows=2232 width=803) (actual time=0.002..1.568 rows=2232 loops=1)
Total runtime: 787.678 ms
它是顺序与限制的结合
如果没有索引(ord,sort_name),那么我打赌这就是性能低下的原因。或者,对于这个特定的查询,可能需要一个索引(start\u ref、ord、sort\u name)。最后,由于这种连接,可能左/第一个表就是您的ORDER BY标准所适用的表。它是ORDER BY和LIMIT的组合
如果没有索引(ord,sort_name),那么我打赌这就是性能低下的原因。或者,对于这个特定的查询,可能需要一个索引(start\u ref、ord、sort\u name)。最后,由于该联接,可能左/第一个表就是应用ORDER BY条件的表。在联接中似乎花费了很长时间。postgresql.conf中的默认内存设置对于任何现代计算机来说都太低。你记得要把它们往上推吗?那好像是很久以前的事了。postgresql.conf中的默认内存设置对于任何现代计算机来说都太低。您是否记得将它们放大?在我看来,必须使用DISTINCT
删除联接产生的重复项。所以我的问题是,为什么首先要生产复制品?我不完全确定ORM生成的这个查询意味着什么,但是如果重写它是一个选项,您当然可以重写它,以防止出现重复。例如,在
中使用:
SELECT "resources_resource"."id",
"resources_resource"."heading",
"resources_resource"."name",
"resources_resource"."old_name",
"resources_resource"."clean_name",
"resources_resource"."sort_name",
"resources_resource"."see_also_id",
"resources_resource"."referenced_passages",
"resources_resource"."resource_type",
"resources_resource"."ord",
"resources_resource"."content",
"resources_resource"."thumb",
"resources_resource"."resource_origin"
FROM "resources_resource"
WHERE "resources_resource"."id" IN (
SELECT "resources_passageresource"."resource_id"
FROM "resources_passageresource"
WHERE "resources_passageresource"."start_ref" >= 66001001
)
ORDER BY "resources_resource"."ord" ASC, "resources_resource"."sort_name" ASC LIMIT 5
或使用存在
:
SELECT "resources_resource"."id",
"resources_resource"."heading",
"resources_resource"."name",
"resources_resource"."old_name",
"resources_resource"."clean_name",
"resources_resource"."sort_name",
"resources_resource"."see_also_id",
"resources_resource"."referenced_passages",
"resources_resource"."resource_type",
"resources_resource"."ord",
"resources_resource"."content",
"resources_resource"."thumb",
"resources_resource"."resource_origin"
FROM "resources_resource"
WHERE EXISTS (
SELECT *
FROM "resources_passageresource"
WHERE "resources_passageresource"."resource_id" = "resources_resource"."id"
AND "resources_passageresource"."start_ref" >= 66001001
)
ORDER BY "resources_resource"."ord" ASC, "resources_resource"."sort_name" ASC LIMIT 5
当然,如果完全重写查询是可以接受的,我还将删除列名前面的长表名。考虑下面的例子,例如< <代码> >重写查询>:
在我看来,DISTINCT
必须用于删除联接产生的重复项。所以我的问题是,为什么首先要生产复制品?我不完全确定ORM生成的这个查询意味着什么,但是如果重写它是一个选项,您当然可以重写它,以防止出现重复。例如,在
中使用:
SELECT "resources_resource"."id",
"resources_resource"."heading",
"resources_resource"."name",
"resources_resource"."old_name",
"resources_resource"."clean_name",
"resources_resource"."sort_name",
"resources_resource"."see_also_id",
"resources_resource"."referenced_passages",
"resources_resource"."resource_type",
"resources_resource"."ord",
"resources_resource"."content",
"resources_resource"."thumb",
"resources_resource"."resource_origin"
FROM "resources_resource"
WHERE "resources_resource"."id" IN (
SELECT "resources_passageresource"."resource_id"
FROM "resources_passageresource"
WHERE "resources_passageresource"."start_ref" >= 66001001
)
ORDER BY "resources_resource"."ord" ASC, "resources_resource"."sort_name" ASC LIMIT 5
或使用存在
:
SELECT "resources_resource"."id",
"resources_resource"."heading",
"resources_resource"."name",
"resources_resource"."old_name",
"resources_resource"."clean_name",
"resources_resource"."sort_name",
"resources_resource"."see_also_id",
"resources_resource"."referenced_passages",
"resources_resource"."resource_type",
"resources_resource"."ord",
"resources_resource"."content",
"resources_resource"."thumb",
"resources_resource"."resource_origin"
FROM "resources_resource"
WHERE EXISTS (
SELECT *
FROM "resources_passageresource"
WHERE "resources_passageresource"."resource_id" = "resources_resource"."id"
AND "resources_passageresource"."start_ref" >= 66001001
)
ORDER BY "resources_resource"."ord" ASC, "resources_resource"."sort_name" ASC LIMIT 5
当然,如果完全重写查询是可以接受的,我还将删除列名前面的长表名。考虑下面的例子,例如< <代码> >重写查询>:
您是否有此字段的索引
resources\u resource.id
和resources\u passageresource.resource\u id
johntotetwoo有一个好问题。您的WHERE子句正在命中resources\u passageresource.start\u ref上的索引。。。那些成本值呢?分析的输出是什么?在resources\u resource.ord
和.id
上的单个索引,以及在resources\u passageresource.resource\u id
和上的单个索引。在这个字段上有索引吗resources\u resource.id
和resources\u passageresource.resource\u id
johntotetwoo有一个好问题。您的WHERE子句正在命中resources\u passageresource.start\u ref上的索引。。。那么这些成本值呢?分析的输出是什么?在resources\u resource.ord
和.id
上的单个索引,以及在resources\u passageresource.resource\u id
和上的单个索引。计划者估计有326行要按以下顺序排序。。。应该是毫秒而不是秒。OP需要对解释进行后期分析,以获得更好的图片。它还需要对唯一的过程进行排序,以实现DISTINCT。有序索引扫描并不总是比seq scans+sort好,事实上,由于搜索时间的原因,它们通常会差得多。我在ord
上有索引,但在sort\u name
上没有索引,我想我真的不需要在sort\u name
上排序。我将尝试删除它。仅从ORDER BY中删除sort\u name
没有帮助,但删除ORDER BY会将查询降低到800ms。这是一个显著的改进,但速度仍然慢得令人无法接受。计划者估计有326行要按。。。应该是毫秒而不是秒。OP需要对解释进行后期分析,以获得更好的图片。它还需要对唯一的过程进行排序,以实现DISTINCT。有序索引扫描并不总是比seq scans+sort好,事实上,由于搜索时间的原因,它们通常会差得多。我在ord
上有索引,但在sort\u name
上没有索引,我想我真的不需要在sort\u name
上排序。我将尝试删除它。仅从ORDER BY中删除sort\u name
没有帮助,但删除ORDER BY会将查询降低到800ms。有明显的改善,但仍然慢得令人无法接受。对不起,应该怎么做?如果存在DISTINCT
子句,并且您只从两个表中的一个表中提取行,并且(可能)包括PK列,则在
中内部将联接替换为?将这两种查询相互匹配涉及多个因素,因此我想,教查询规划者这么做可能不是一件容易的事。不过,作为一个软件类,我对查询计划器知之甚少。但你至少可以说PostgreSQL的一个还不够聪明(现在?)。对不起,你应该怎么做?当出现DISTINCT
子句并且正在拉取时,在内部将联接替换为