使用左外连接进行慢查询并且为空条件

时间:2009-07-01 15:12:21

标签: sql postgresql

我有一个简单的查询(postgresql,如果重要的话),检索some_user的所有项目,不包括她在心愿单上的项目

select i.* 
from core_item i 
left outer join core_item_in_basket b on (i.id=b.item_id and b.user_id=__some_user__)
where b.on_wishlist is null;

以上查询运行在~50000ms(是的,数字是正确的)。 如果我删除“b.on_wishlist为null”条件或使其“b.on_wishlist is not null”,则查询将在大约50ms内运行(相当大的变化)。

查询有更多的连接和条件,但这是无关紧要的,因为只有这个减慢了它。

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

  • core_items有~10,000条记录
  • core_user有~5000条记录
  • core_item_in_basket有~2.000
  • 记录(其中约有50%有记录) on_wishlist = true,其余为空)

我在这两个表上没有任何索引(除了id和外键)。

问题是:我应该怎么做才能让这个更快跑?我今晚有一些想法可以查看,但我希望你们能帮助我们,同样。

谢谢!

4 个答案:

答案 0 :(得分:5)

尝试使用not exists:

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__)

答案 1 :(得分:2)

您可能想要详细解释此查询的目的 - 正如某些技术所做的那样,有些技术没有意义,具体取决于用例。

你多久运行一次?

它是仅为1个用户运行,还是在某种循环中为所有用户运行?

执行:解释分析并将输出放在explain.depesz.com上,这样你就会明白它为什么这么慢。

答案 2 :(得分:2)

很抱歉添加第二个答案,但stackoverflow不允许我正确格式化评论,因为格式化是必不可少的,我必须发布答案。

几个选项:

  1. CREATE INDEX q ON core_item_in_basket(user_id,item_id)WHERE on_wishlist为null;
  2. 相同的索引,但改变了列中的列顺序。
  3. SELECT i。* FROM core_item i WHERE i.id not in(select item_id FROM core_item_in_basket WHERE on_wishlist为null AND user_id = __some_user__); (此查询可以从第1点的索引中受益,但不会从索引#2中受益。
  4. 来自core_item的SELECT *,其中id为(从core_item中选择id EXCEPT select item_id FROM core_item_in_basket WHERE on_wishlist为null AND user_id = __some_user __);
  5. 让我们知道结果:)

答案 3 :(得分:1)

您是否尝试在on_wishlist上添加索引

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

当您在on_wishlist子句中放置where条件时,这将导致它(取决于查询器所决定的内容)在执行连接后进行评估,该比较必须可以为连接产生的每一行完成。 core_itemscore_item_in_basket表都非常大,并且您没有该列的索引,因此查询优化器几乎没有,这可能会导致查询时间过长

core_user的大小应该没有影响(因为它没有在查询中引用)。