我整理了一个我正在纠结的查询的简化版本:
WITH cte AS (
SELECT
num_serves_p1 AS num_serves, player_id_p1 AS player_id, location, date_
FROM
table1
UNION ALL SELECT
num_serves_p2 AS num_serves, player_id_p2 AS player_id, location, date_
FROM
table1
)
SELECT
id_, SUM(cte.num_serves)
FROM
table1 AS t
JOIN
cte ON cte.player_id = t.player_id_p1
AND cte.location = t.location
AND cte.date_ < t.date_
WHERE
t.id_ = 12345
字符串
目前,这需要一分钟以上的时间来运行大约一百万行。
如果我去掉UNION_ALL
的第二部分,给予:
WITH cte AS (
SELECT
num_serves_p1 AS num_serves, player_id_p1 AS player_id, location, date_
FROM
table1
)
SELECT
id_, SUM(cte.num_serves)
FROM
table1 AS t
JOIN
cte ON cte.player_id = t.player_id_p1
AND cte.location = t.location
AND cte.date_ < t.date_
WHERE
t.id_ = 12345
型
或者UNION_ALL
的第一部分给予我:
WITH cte AS (
SELECT
num_serves_p2 AS num_serves, player_id_p2 AS player_id, location, date_
FROM
table1
)
SELECT
id_, SUM(cte.num_serves)
FROM
table1 AS t
JOIN
cte ON cte.player_id = t.player_id_p1
AND cte.location = t.location
AND cte.date_ < t.date_
WHERE
t.id_ = 12345
型
然后这些查询中的任何一个都在0.1秒内运行。
所以我认为我所有的索引都很好,但问题在于使用UNION_ALL
。考虑到性能上的巨大差异,我的直觉是,在第一个查询中,CTE加载了table1(x2)中的所有行,而在第二个和第三个查询中,CTE只加载了连接所需的行。
我意识到我可以创建两个CTE并简单地将结果相加,但是在某些时候,我将计算依赖于日期排序UNION_ALL
CTE的字段。
为什么我看到第一个查询的性能很差,我能做些什么呢?
最后一点:我没有包括所有常见的表描述等,因为这实际上是一个伪查询。我认为有足够的东西可以继续下去,因为我已经将UNION_ALL
的使用隔离为可能的问题。我也不知道如何生成足够的数据来说明这个问题。手指交叉在上面就足够了。
1条答案
按热度按时间ryevplcw1#
优化器对于联合、联接、CTE不够智能,无法将“id=”一路传播。相反,它正在评估
UNION
的每个部分,创建一个包含所有这些行的临时表,并可能构建一个索引以帮助下一步。如果对每个表副本执行
SUM
操作,然后将它们加在一起,则运行速度可能会更快。(我甚至不能判断这是否是一个有效的转换,优化器甚至不会尝试它。更多
字符串
-->
型
或者,这样可能更好:
型
**更多 *
型