问题描述
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行。
解决方法
SQL优化器在“裸”表上的信息比在“计算”表上的信息更多。因此,更容易优化两个CTE。
在使用索引的数据库中,这可能会影响索引的使用。在Redshift中,这可能会导致其他数据移动。
不过,在这种特殊情况下,我怀疑问题可能与通过JOIN
操作进行过滤有关。 UNION
的开销是删除重复项。通过在UNION
之前过滤 ,重复删除比之后过滤更快。
此外,UNION
可能会影响数据的位置,因此第二个版本可能需要其他数据移动。