【发布时间】:2023-03-20 01:10:02
【问题描述】:
我最近注意到一个包含 CTE 的性能不佳的查询。
从运行EXPLAIN 看来,如果我在 CTE 中有 2 个连续表,其中第一个表应用了 WHERE 过滤器,则 postgres 优化器实际上不会限制设置的行,因此第二个表查找速度很慢:
WITH thing_data AS (
SELECT * FROM things WHERE id = '0000000001'
), thing_readings AS (
SELECT thing_timestamp
FROM reading_log_instantaneous_schedule
INNER JOIN thing_data
ON thing_id = thing_data.id
ORDER BY thing_timestamp DESC LIMIT 1
),
SELECT thing_data.*
FROM thing_data
LEFT OUTER JOIN thing_readings
ON thing_data.id = thing_readings.thing_id
基本上读数表中的内连接没有受益于INNER JOIN thing_data on thing_id = thing_data.id,实际上是对读数表中的所有行进行扫描。
是否可以让优化器注意到我已将thing_data 记录集限制为一行,从而使后续连接变得快速,而不是超级慢?
编辑:对匿名性不佳的查询表示歉意。
我创建了一个 SQLFiddle 来演示我遇到的问题 - 我仍然需要添加 2 个 WHERE 子句(不利于代码可维护性等) - 即使忘记 CTE 并按照 Craig 的建议使用常规连接表,问题仍然存在.我更习惯使用 SQL Server 转换架构时没有这个问题。
【问题讨论】:
-
如果您在过滤器中也使用 WHERE id = '0000000001' 来读取_log_instantaneous_schedule 会怎样?
-
我的示例已简化,您的建议并不总是适用于我的用例。
-
它甚至被过度简化了:thing_readings CTE 在选择列表中没有 thing_id。
-
尽管
SELECT在子查询中使用了reading,但您并没有使用它。正如所写,我认为您的“简化”查询仍然只是进行EXISTS测试的一种令人难以置信的迂回方式。readings.reading应该包含在最终选择列表中还是应该在外部 where 子句中进行测试?严重匿名的查询是在浪费每个人的时间,-1。 请解释查询的目的。
标签: postgresql common-table-expression