PostgreSQL中的查询优化
我有一个非常简单的查询,总运行时间很大。你能告诉我如何优化它吗 以下是解释和分析: 查询:PostgreSQL中的查询优化,sql,postgresql,Sql,Postgresql,我有一个非常简单的查询,总运行时间很大。你能告诉我如何优化它吗 以下是解释和分析: 查询: select wpis_id from spoleczniak_oznaczone where etykieta_id in( select tag_id from spoleczniak_subskrypcje where postac_id = 376476 ); 斯波莱茨尼亚克奥扎克区: Column | Type |
select wpis_id from spoleczniak_oznaczone
where etykieta_id in(
select tag_id
from spoleczniak_subskrypcje
where postac_id = 376476
);
斯波莱茨尼亚克奥扎克区:
Column | Type | Modifiers
-------------+---------+--------------------------------------------------------------------
id | integer | not null default nextval('spoleczniak_oznaczone_id_seq'::regclass)
etykieta_id | integer | not null
wpis_id | integer | not null
Indexes:
"spoleczniak_oznaczone_pkey" PRIMARY KEY, btree (id)
"spoleczniak_oznaczone_etykieta_id" btree (etykieta_id)
"spoleczniak_oznaczone_wpis_id" btree (wpis_id)
Foreign-key constraints:
"spoleczniak_oznaczone_etykieta_id_fkey" FOREIGN KEY (etykieta_id) REFERENCES spoleczniak_etykiety(id) DEFERRABLE INITIALLY DEFERRED
"spoleczniak_oznaczone_wpis_id_fkey" FOREIGN KEY (wpis_id) REFERENCES spoleczniak_tablica(id) DEFERRABLE INITIALLY DEFERRED
spoleczniak_subskrypcje:
Column | Type | Modifiers
-----------+---------+----------------------------------------------------------------------
id | integer | not null default nextval('spoleczniak_subskrypcje_id_seq'::regclass)
postac_id | integer | not null
tag_id | integer | not null
Indexes:
"spoleczniak_subskrypcje_pkey" PRIMARY KEY, btree (id)
"spoleczniak_subskrypcje_postac_id" btree (postac_id)
"spoleczniak_subskrypcje_postac_tag" btree (postac_id, tag_id)
"spoleczniak_subskrypcje_tag_id" btree (tag_id)
Foreign-key constraints:
"spoleczniak_subskrypcje_postac_id_fkey" FOREIGN KEY (postac_id) REFERENCES postac_postacie(id) DEFERRABLE INITIALLY DEFERRED
"spoleczniak_subskrypcje_tag_id_fkey" FOREIGN KEY (tag_id) REFERENCES spoleczniak_etykiety(id) DEFERRABLE INITIALLY DEFERRED
从查询计划来看,大部分时间似乎都涉及到where子句的in部分。似乎使用了适当的索引
select o.wpis_id
from spoleczniak_oznaczone o
inner join spoleczniak_subskrypcje s on s.tag_id = o.etykieta_id
where s.postac_id = 376476
…看起来功能相同,但以不同的方式尝试,可能会生成不同的查询计划
另外,正如@wildplasser所说的,确保统计数据是最新的,并且索引已被碎片整理(我自己不知道如何在PostgreSQL中进行碎片整理)
编辑:正如@a_horse_with_no_name在下面的评论中所说的那样,我建议的查询可以返回原始查询无法返回的重复项。不知道你的数据,我不知道它是否会。这是一个需要记住的警告。从查询计划来看,大部分时间似乎都在计算where子句的in部分。似乎使用了适当的索引
select o.wpis_id
from spoleczniak_oznaczone o
inner join spoleczniak_subskrypcje s on s.tag_id = o.etykieta_id
where s.postac_id = 376476
…看起来功能相同,但以不同的方式尝试,可能会生成不同的查询计划
另外,正如@wildplasser所说的,确保统计数据是最新的,并且索引已被碎片整理(我自己不知道如何在PostgreSQL中进行碎片整理)
编辑:正如@a_horse_with_no_name在下面的评论中所说的那样,我建议的查询可以返回原始查询无法返回的重复项。不知道你的数据,我不知道它是否会。这是一个需要记住的警告。您为什么喜欢在中使用
和子查询来:
select wpis_id
from spoleczniak_oznaczone, spoleczniak_subskrypcje
where etykieta_id = tag_id
and postac_id = 376476
我想对于查询优化者来说,简单连接可能更简单。您为什么喜欢在
中使用,并使用子查询来:
select wpis_id
from spoleczniak_oznaczone, spoleczniak_subskrypcje
where etykieta_id = tag_id
and postac_id = 376476
我想对于查询优化者来说,简单连接可能更简单。这应该是等效的(在大多数情况下,将生成相同的查询计划)
这应该是等效的(在大多数情况下,将生成相同的查询计划)
尝试替换此索引:
"spoleczniak_oznaczone_etykieta_id" btree (etykieta_id)
索引位于(etykieta\u id,wpis\u id)
。这样,DB就可以只执行索引扫描(而不需要从表中获取整行,这会占用访问时间) 尝试替换此索引:
"spoleczniak_oznaczone_etykieta_id" btree (etykieta_id)
索引位于(etykieta\u id,wpis\u id)
。这样,DB就可以只执行索引扫描(而不需要从表中获取整行,这会占用访问时间) 请同时添加实际查询。。。。以及生成的查询计划,请。。。您的表有有效的统计数据吗?您是否对数据库设置进行了任何调整?@wildplasser:查询计划就在那里。explain.depesz.com的链接这是哪个Postgres版本?在9.2上,我希望它在indexspoleczniak\u subskrypcje\u postac\u标签上使用仅索引扫描。另外,您的行估计值有点偏离。因此,如果你仔细阅读计划,你可能会发现你的统计数据是错的。运行真空分析两个表上的代码>也请添加实际查询。。。。以及生成的查询计划,请。。。您的表有有效的统计数据吗?您是否对数据库设置进行了任何调整?@wildplasser:查询计划就在那里。explain.depesz.com的链接这是哪个Postgres版本?在9.2上,我希望它在indexspoleczniak\u subskrypcje\u postac\u标签上使用仅索引扫描。另外,您的行估计值有点偏离。因此,如果你仔细阅读计划,你可能会发现你的统计数据是错的。运行真空分析两个表上的代码>。联接不一定是
条件下的的替换。我不这么认为postac\u id
不是唯一的,标签id也不是唯一的。因此,一个postac_id
可以多次返回相同的tag_id
,然后连接的结果将不同于查询中的结果……我错过了一些东西。你说得对-谢谢!我将对答案进行注释。@a_horse_和_no_name:在这种情况下,您是错的:in(…)
在主查询中使用子查询之前,从子查询的结果中删除重复项(和空值)。@wildplasser:没错,这就是为什么联接会返回不同的结果。联接不一定是
条件下的
的替代品。我不这么认为postac\u id
不是唯一的,标签id也不是唯一的。因此,一个postac_id
可以多次返回相同的tag_id
,然后连接的结果将不同于查询中的结果……我错过了一些东西。你说得对-谢谢!我将对答案进行注释。@a_horse_with_no_name:在这种情况下,您是错的:in(…)
在主查询中使用子查询之前,会从子查询的结果中删除重复项(和空值)。@wildplasser:没错,这就是为什么联接会返回不同的结果。对于OP:如果您仔细阅读计划,你可以看到你的统计数据是错的。运行真空分析代码>在两个表上。我做了。在运行该查询之前。似乎不合逻辑:子查询中估计的行数仍然是非常错误的。对OP:如果仔细阅读计划,您可以看到您的统计数据已关闭。运行真空分析代码>在两个表上。我做了。在运行该查询之前。似乎不合逻辑:子查询中估计的行数仍然严重错误。速度更快,但不够快(原始查询约800毫秒,在该索引更改后约500毫秒)。能否附加带缓冲区参数的解释计划?您的查询返回>500.000行,这可能是原因。它现在确实执行仅索引扫描,但需要循环23次。spoleczniak_subskrypcje中的一对(postac_id,tag_id)
不应该是唯一的吗?如果我没弄错的话,这张表是供人们订阅标签的,对吗?如果这是真的,那么您可以在(…)中尝试@simonatrcl query-replace
w