Sql 具有左外部联接且为空条件的慢速查询

Sql 具有左外部联接且为空条件的慢速查询,sql,postgresql,Sql,Postgresql,我有一个简单的查询postgresql,如果这很重要的话,它会检索一些用户的所有项目,不包括她愿望列表上的项目: 上述查询运行时间约为50000ms是的,数字正确。 如果我删除b.on_wishlist is null条件或使其为b.on_wishlist is not null,查询将在50毫秒内运行,这是一个相当大的变化 查询有更多的连接和条件,但这与此无关,因为只有这一个会减慢查询速度 有关数据库大小的一些信息: 核心项目约有10000条记录 core_用户有约5000条记录 _篮中的核心

我有一个简单的查询postgresql,如果这很重要的话,它会检索一些用户的所有项目,不包括她愿望列表上的项目:

上述查询运行时间约为50000ms是的,数字正确。 如果我删除b.on_wishlist is null条件或使其为b.on_wishlist is not null,查询将在50毫秒内运行,这是一个相当大的变化

查询有更多的连接和条件,但这与此无关,因为只有这一个会减慢查询速度

有关数据库大小的一些信息:

核心项目约有10000条记录 core_用户有约5000条记录 _篮中的核心_项目约有2.000 其中约50%的记录 在_wishlist=true时,其余为null 除了这两个表上的ID和外键之外,我没有任何索引

问题是:我应该怎么做才能让它跑得更快?今天晚上我自己也有一些想法,但如果可能的话,我也希望你们能帮忙

谢谢

尝试使用不存在的:

select i.* 
from   core_item i 
where  not exists (select * from core_item_in_basket b where i.id=b.item_id and b.user_id=__some_user__)
你试过在你的愿望清单上添加索引吗

似乎需要为查询中的每一行检查此列。如果表那么大,这可能会对查询速度产生相当大的影响

当您将on_wishlist条件放在where子句中时(这将导致它取决于执行联接后查询规划器决定计算的内容),必须对联接产生的每一行进行比较。core_items和core_item_in_basket表都非常大,并且您没有该列的索引,因此查询优化器所要做的事情很少,这可能导致查询时间过长


core_用户的大小应该没有影响,因为它在查询中没有被引用

您可能想更多地解释这个查询的目的,因为有些技术是有意义的,有些是没有意义的,这取决于用例

你多久运行一次

它是只为一个用户运行,还是在某种循环中为所有用户运行


执行:解释、分析并打开输出,以便您了解为什么它如此缓慢。

很抱歉添加第二个答案,但stackoverflow不允许我正确设置注释格式,而且由于格式设置非常重要,我必须发布答案

两种选择:

在核心项目上创建索引q,该项目在项目篮用户id中,项目id中,其中项目愿望列表为空; 相同的索引,但更改其中列的顺序。 从core_item i中选择i.*,其中i.id不在SelectItem_id中,从core_item_中选择id,其中on_wishlist为null,user_id=u some_user_uuu;此查询可以受益于第1点的索引,但不会受益于第2点的索引。 从core_项目中选择*从core_项目中选择id从core_项目中选择id,但从core_项目中选择项目id从_篮子中选择,其中on_wishlist为空,并且用户_id=uu某些用户_uuuuuuuu;
让我们知道结果:

也许您可以查看执行计划以了解问题所在。理论上,如果余额为50/50,则请求“为空”或“不为空”必须具有相同的执行计划。表的空统计信息一定是错误的@天蝎座:不完全是。记住,这是一个外部连接。core_item_in_basket的空统计数据确实是50/50,但查询尝试将core_item中的每个记录与core_item_in_basket中的记录进行匹配,在联接的右侧产生大量额外的空值。有两种行匹配您的条件,其中b.on_wishlist为空1。核心项目中的行与核心项目篮中核心项目中的行不匹配;2.core_item中的行在core_item_in_basket中确实有匹配的行,但其中一些匹配项在_wishlist上匹配为null。您想要两组行吗?@AlexKuznetsov是的,两者都忽略了b.on_wishlist为null条件,这似乎是这里的减速因素。啊,然后将其添加到存在的位置。此外,在您的连接中,请尝试在Condititono上向连接中添加空值,这也没有帮助。多年来,PostgreSQL学会了自动优化类似的东西。不,wishlist上的索引没有什么意义,因为它只能是真的或假的null@depesz当然,我会在大约2小时后回家,因为我讨厌通过ssh在手机上写查询。顺便说一句,我实际上想直接问你关于这部电影的问题,但我决定不为我所有的PSQL问题打扰你:所以,回答你的问题:a这个查询的目的是让X部下一部电影被评级,但不包括那些在某人的愿望清单上的电影。b每次用户想要在此处对随机电影进行评分时,它都会为一个用户运行-尽管我们将结果限制为10,缓存它们并在对10部下一部电影进行评级后再次运行相同的查询c我在上面展示的真实查询是一个简化版本,解释分析在这里:d,这里是没有愿望列表条件的相同查询:答案4是正确的。当你考虑它的时候,它是很有意义的。我们不想有一个外部连接真的是为了什么?只是排除了愿望清单上的少数项目
. 索引在这里是不好的,因为问题不在于核心\u项目\u in\u basket表,它很小,而是不必要的连接。所有已签入并正在生产中,请在签出,非常感谢depesz再次保存我的屁股:PBTW,如果您感兴趣,新的解释分析在这里:感谢您提供选项2!
select i.* 
from   core_item i 
where  not exists (select * from core_item_in_basket b where i.id=b.item_id and b.user_id=__some_user__)