【问题标题】:Why are subqueries in selects slow compared to joins?为什么选择中的子查询比连接慢?
【发布时间】:2016-12-22 21:09:56
【问题描述】:

我有两个问题。第一个从另一个表中检索一些聚合作为列,使用 select 中的子查询(返回所有行的列的字符串连接)。

第二个查询通过在 from 中进行子选择来执行相同的操作,然后加入结果。然而,第二个查询在加入之前对整个表进行聚合,但速度要快得多(286 毫秒对 7645 毫秒)。

我不明白为什么子查询慢得多,而第二个查询在一个有 175k 行的表上进行聚合(在 postgresql 9.5 上)。使用子选择更容易集成到查询构建器中,所以我想使用它,当记录数量增加时,第二个查询会变慢。有没有办法提高子选择的速度?

查询 1:

select kp_No, 
(select string_agg(description,E'\n') from (select nt_Text as description from fgeNote where nt_kp_No=fgeContact.kp_No order by nt_No DESC limit 3) as subquery) as description 
from fgeContact 
where kp_k_No=729;

说明:https://explain.depesz.com/s/8sL

查询 2:

select kp_No, NoteSummary 
from fgeContact 
LEFT JOIN 
    (select nt_kp_No, string_agg(nt_Text,E'\n') as NoteSummary 
        from 
            (select nt_kp_No, nt_Text from fgeNote ORDER BY nt_No DESC) as sortquery 
        group by nt_kp_No) as joinquery 
    ON joinquery.nt_kp_No=kp_No  
where kp_k_No=729;

说明:https://explain.depesz.com/s/yk9W

【问题讨论】:

  • 问这个问题就像“为什么把 12 个鸡蛋放在篮子里,一个人拿来比一个一个拿来更快”。因为篮子就是为此而生的,因为你只有两只手。等

标签: performance postgresql


【解决方案1】:

这是因为在第二个查询中,您在一次扫描中检索所有寄存器,而在第一个查询中,子查询针对主表的每个选定寄存器执行一次,因此,每次都应再次扫描表.

即使进行了索引扫描,通常比扫描整个桌子更昂贵,甚至是顺序的(实际上,在选择多个寄存器时,顺序扫描速度比索引扫描快得多,因为索引意味着索引意味着一些架子),并且只选择了索引)有趣的寄存器。

但这也取决于实际的数据分布。完全有可能,对于 kp_k_No 的不同值,如果表仅包含具有该参数值的一行或几行,则第二次查询会变得更快。

这是一个测试和猜测会发生的不同情况的问题......

【讨论】:

  • 但这能解释差异的大小吗?对于特定的 kp_k_No,我得到一个包含 92 行的列表。而且,对于这些行,fgeNote 中总共只有 96 行。使用子查询,此查询大约需要 3 秒。加入的版本大约需要 20 毫秒。该版本必须获取、排序和聚合完整的 fgeNote 表(其中包含 175k 条记录),然后执行连接。这似乎需要更多的工作,而且 3 秒执行这 92 行的子查询似乎不成比例。感谢您的回复 b.t.w.
猜你喜欢
  • 1970-01-01
  • 2014-03-13
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
  • 1970-01-01
相关资源
最近更新 更多