首页 > 解决方案 > Postgres执行合并中的所有子查询

问题描述

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 ...)
);

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

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

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

那么我是否在做任何不好的做法,出于性能原因单独运行查询会更好吗?

编辑:

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

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

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

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

标签: sqldatabasepostgresql

解决方案


对于单独的SELECT查询,我建议使用UNION ALL/LIMIT 1代替。根据您的小提琴

(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<>在这里摆弄

出于三个原因:

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

  2. 您可以将实际NULL值与“无行”区分开来。由于user_idPK 在示例中(因此,NOT NULL),因此问题不会在示例中出现。NULL但是对于可以是,COALESCE不能区分两者的表达式,“无行”被强制NULL用于查询目的。看:

  3. 快点。

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

有关的:


推荐阅读