【问题标题】:Postgres all subqueries in coalesce executedPostgres执行合并中的所有子查询
【发布时间】:2020-03-28 21:11:27
【问题描述】:

Postgres 中的 COALESCE 是一个返回第一个参数不为空的函数。 所以我在子查询中使用了合并,例如:

SELECT COALESCE (
 ( SELECT * FROM users WHERE... ORDER BY ...),
 ( SELECT * FROM users WHERE... ORDER BY ...),
 ( SELECT * FROM users WHERE... ORDER BY ...),
 ( SELECT * FROM users WHERE... ORDER BY ...)
);

我更改了任何查询中的 where,它们包含很多参数和 CASE,还有不同的 ORDER BY 子句。 这是因为我总是想返回一些东西,但要优先考虑。

我在发出EXPLAIN ANALYZE 时注意到的是,尽管第一个查询实际上返回非空值,但任何查询都会被执行。 我希望引擎只运行第一个查询,如果它返回不为空,则不运行以下查询。

这样我的表现可能会很差。

那么我有什么不好的做法吗?出于性能原因单独运行查询会更好吗?

编辑:

对不起,我没有选择 * 但我只选择了一列。我没有发布我的代码,因为我对我的查询不感兴趣,但这是一个了解引擎如何工作的通用问题。所以我在这里复制了一个非常简单的小提琴http://sqlfiddle.com/#!17/a8aa7/4

我可能错了,但我认为它的行为与我所说的一样:尽管第一个子查询已经返回非空值,但它运行所有子查询

编辑 2:好的,我现在才读到它说从未执行过。所以其他两个查询没有被执行。让我感到困惑的是它们被包含在查询计划中。

无论如何,这对我的问题仍然很重要。出于性能原因单独运行所有查询是否更好?因为看起来即使第一个返回非空值,其他两个子查询也会降低性能

【问题讨论】:

  • 你能编辑你的问题并包括你想要达到的目标吗?举例说明您拥有的数据、您希望获得的结果以及您尝试获得结果的思维过程或 SQL。 COALESCE 最好像 coalesce(new_salary, old_salary, 5000) 这样使用,这意味着,如果 new_salary 为空,则使用 old_salary。如果 old_salary 为空,请使用 5000。
  • 该查询一开始就不是有效的 SQL。您不能将coalesce()select * 结合使用。 coalesce() 适用于单个值,而不适用于表的所有列。如果您退后一步并解释您要解决的潜在问题,您可能会得到更好的答案。请edit您的问题(通过单击其下方的edit 链接)并添加一些示例数据和基于该数据的预期输出为formatted text。请参阅here,了解有关如何创建美观的文本表的一些提示。
  • 我认为这不是您的实际代码。所有这些查询都应返回 1 行和 1 列以在 COALESCE 内有效。还要确保 COALESCE 只评估确定结果所需的参数;也就是说,不会从postgresql.org/docs/current/… 评估第一个非空参数右侧的参数
  • 只是为了证明我之前的评论检查这个:dbfiddle.uk/… 运行良好,因为没有评估 coalesce 的第二个参数。如果它被评估,那么查询将失败并出现错误,因为递归 cte 将超过最大迭代次数。
  • @a_horse_with_no_name

标签: sql database postgresql


【解决方案1】:

对于单独的SELECT 查询,我建议改用UNION ALL / LIMIT 1。基于your fiddle

(select user_id from users order by age limit 1)  -- misleading example, see below
UNION ALL
(select user_id from users where user_id=1)
UNION ALL
(select user_id from users order by user_id DESC limit 1)
LIMIT 1;

db小提琴here

出于三个原因:

  1. 适用于任何 SELECT 列表:单个表达式(您的小提琴)、多个或整行(您在问题中的示例)。

  2. 您可以将实际的NULL 值与“无行”区分开来。由于user_id 是示例中的PK(因此,NOT NULL),因此问题无法在示例中显现。但是对于可以为NULL 的表达式,COALESCE 无法区分两者,出于查询的目的,“无行”被强制转换为NULL。见:

  3. 更快。

除此之外,您在示例中的第一个 SELECT 使这成为了一场疯狂的追逐。如果至少有一行,则返回一行。在这种情况下,剩下的就是噪音。

相关:

【讨论】:

  • 感谢您的回答,这很有趣。无论如何,我没有发现任何与性能相关的差异,而不是在选择中使用合并单个字段
猜你喜欢
  • 1970-01-01
  • 2021-05-27
  • 2014-10-22
  • 1970-01-01
  • 2022-10-12
  • 2021-07-26
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多