【发布时间】:2020-09-16 09:00:19
【问题描述】:
我有一个 SQL 查询,内容如下:
WITH a AS (
SELECT *
FROM table1
INNER JOIN table3 ON table1.id = table3.id
WHERE table1.condition = 'something'
),
b AS (
SELECT *
FROM table2
INNER JOIN table3 ON table2.id = table3.id
WHERE table2.condition = 'something else'
),
combined AS (
SELECT *
FROM a
UNION
SELECT *
FROM b
)
SELECT *
FROM combined
我把它改写为:
WITH a AS (
SELECT *
FROM table1
WHERE table1.condition = 'something'
),
b AS (
SELECT *
FROM table2
WHERE table2.condition = 'something else'
),
combined AS (
SELECT *
FROM (
SELECT *
FROM a
UNION
SELECT *
FROM b
) union
INNER JOIN table3 ON union.id = table3.id
)
SELECT *
FROM combined
我预计这可能会更高效,因为它只执行JOIN 一次,或者至少不会影响执行时间。我惊讶地发现,现在查询的运行时间几乎是原来的两倍。
这没问题,因为它以前运行得很好,我只是出于个人风格偏好而重新编写了它,所以我会坚持原来的。但我不是数据库/SQL 方面的专家,所以我很想知道是否有人可以分享关于为什么第二种方法的性能如此低下的任何见解?
如果有什么不同,那就是 Redshift 数据库,table1 和 table2 的行数都约为 2.5 亿行,table3 的行数约为 100 万行,combined 的行数不到 1000 行。
【问题讨论】:
-
您需要为这两个查询生成执行计划并查看它们的不同之处。在general 中,如果两个查询在逻辑上产生相同的结果,则优化器应该 生成相同的计划。因为在 SQL 中,你告诉系统你想要什么,而不是如何去做。
-
当然第一个更高效:两个连接可以使用索引和统计信息。在 CTE 之后,所有表结构都丢失了,一切都简化为堆表扫描和散列连接。
-
@wildplasser 除非我没有经验专门针对亚马逊红移,否则我认为这不是真的。 CTE 只不过是一个表达式,所有索引和统计信息都会持续到该表达式的最终使用。
-
@GarethD 在 postgres SQL 中,CTE 是一个优化障碍,至少在 PG-12 (IIRC) 之前是这样。 Redshift 是一些较旧的(可能是残废的)PG 版本。
-
@wildplasser 很有趣。我的立场是正确的。
标签: sql amazon-web-services amazon-redshift query-performance