【问题标题】:Does PostgreSQL short-circuit its BOOL_OR() evaluation?PostgreSQL 是否会短路其 BOOL_OR() 评估?
【发布时间】:2017-02-03 08:56:48
【问题描述】:

EXISTSCOUNT(*) 快,因为它可以短路

很多时候,我喜欢在 SQL 中检查事物是否存在。例如,我这样做:

-- PostgreSQL syntax, SQL standard syntax:
SELECT EXISTS (SELECT .. FROM some_table WHERE some_boolean_expression)

-- Oracle syntax
SELECT CASE 
  WHEN EXISTS (SELECT .. FROM some_table WHERE some_boolean_expression) THEN 1 
  ELSE 0 
END
FROM dual

在大多数数据库中,EXISTS 是“短路的”,即数据库可以在找到一行后立即停止在表中查找行。 This is usually much faster than comparing COUNT(*) >= 1 as can be seen in this blog post.

使用EXISTSGROUP BY

有时,我想在GROUP BY 查询中为每个组执行此操作,即我想“聚合”存在值。没有 EXISTS 聚合函数,但 PostgreSQL 幸运地支持 BOOL_OR() 聚合函数,就像下面的语句:

SELECT something, bool_or (some_boolean_expression)
FROM some_table
GROUP BY something

The documentation mentions something about COUNT(*) being slow 因为计算计数需要明显的顺序扫描。但不幸的是,它没有说明BOOL_OR() 被短路。是这样吗? BOOL_OR() 在遇到第一个 TRUE 值时是否停止聚合新值?

【问题讨论】:

  • 执行计划说了什么?但我希望group by 的存在需要从表中读取所有内容,否则无法正确分组数据
  • @a_horse_with_no_name:例如"Aggregate (cost=1.06..1.07 rows=1 width=4)"。 IE。不是很多。这与我放置 COUNT() 聚合函数时的操作相同。或任意数量的聚合函数。不过,我没想到计划会显示这些细节。
  • @LukasEder :你找到标题问题的答案了吗?
  • @MarkKCowan:不。如果我有的话,我会在这里提供答案......

标签: sql postgresql exists boolean-logic boolean-expression


【解决方案1】:

如果要检查是否存在,我一般使用LIMIT/FETCH FIRST 1 ROW ONLY查询:

SELECT .. FROM some_table WHERE some_boolean_expression
FETCH FIRST 1 ROW ONLY

这通常会在第一次命中后停止执行。

可以使用LATERAL 对另一个表中的每一行(组)应用相同的技术。

SELECT * 
  FROM (SELECT something
          FROM some_table
         GROUP BY something
       ) t1
  LEFT JOIN LATERAL (SELECT ...
                        FROM ...
                       WHERE ...
                       FETCH FIRST 1 ROW ONLY) t2
    ON (true)

t2 中,您可以使用与组的任何行匹配的WHERE 子句。它每组只执行一次,并在找到第一个命中后立即中止。但是,这是否表现得更好或更差当然取决于您的搜索谓词和索引。

【讨论】:

  • 您确定LATERAL 加入不会为每个组的内存中聚合带来更多成本吗?正式测量会很有趣。顺便说一句,LEFT JOIN LATERAL .. ON trueCROSS JOIN LATERAL 相同 :)
  • @LukasEder 我提到实际里程取决于您的问题中未提及的细节。 CROSS vs. LEFT:如果横向派生表返回一个空集,则不是。
  • 好的,我会在我这边进行基准测试。会很有趣!您对 CROSS 与 LEFT 的看法是对的,好点。因此,在这种特殊情况下,LEFT 改变了我的查询的语义,使得横向连接对于这个用例毫无意义......
  • @LukasEder 我不明白 LEFT 有什么问题。我猜你想要 t1 的行,不管横向查询是否找到任何东西。否则,当然,CROSS join 会更好。
  • 我认为练习的重点是横向 where 子句可能不会命中任何行——否则,EXISTS 似乎首先是一件奇怪的事情。但是...\off :)
猜你喜欢
  • 2021-09-23
  • 1970-01-01
  • 2013-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多