Jos*_* M. 2 sql-server performance with-statement common-table-expression sql-server-2008
我对WITH语句(CTE)的理解是每个查询执行一次.使用这样的查询:
WITH Query1 AS ( ... )
SELECT *
FROM
    SomeTable t1
    LEFT JOIN Query1 t2 ON ...
如果这导致100行,我希望Query1它只执行一次 - 而不是100次.如果这个假设是正确的,运行整个查询所需的时间大致等于带到时间:跑Query1+选择SomeTable+加入SomeTable到Query1.
我处于以下情况:
Query1 单独运行需要约5秒(400k行).WITH语句后,查询的其余部分LEFT JOIN需要~15秒(400k行).因此,当使用WITH语句和LEFT JOIN就地运行整个查询时,我会期望查询及时完成,而我让它运行超过一个小时,一旦停止它只能达到11k行.
我显然是错的,但为什么呢?
例:
SET NOCOUNT ON;
SET IMPLICIT_TRANSACTIONS ON;
CREATE TABLE MyTable (MyID INT  PRIMARY KEY);
GO
INSERT  MyTable (MyID)
VALUES  (11), (22), (33), (44), (55);
PRINT 'Test MyCTE:';
WITH MyCTE
AS (
    SELECT  *, ROW_NUMBER()OVER(ORDER BY MyID) AS RowNum
    FROM    MyTable
)
SELECT  *
FROM    MyCTE crt
LEFT JOIN MyCTE prev ON crt.RowNum=prev.RowNum+1;
ROLLBACK;
如果您在SSMS中运行以前的脚本(按Ctrl+M- >实际执行计划),那么您将获得上次查询的执行计划:

在这种情况下,CTE对crt别名执行一次,对别名执行五(!)次prev,对于每一行执行一次crt.
那么,这个问题的答案
WITH语句是每个查询执行一次还是每行执行一次?
是both:每个查询(crt)一次,每行prev一次(每次为一次crt).
要优化此查询,首先,1)您可以尝试将CTE(MyCTE或Query)的结果存储到表变量或临时表中
2)将此表的主键定义为连接列,
3)重写最终查询以使用此表变量或临时表.
当然,您可以尝试重写最终查询,而无需在CTE之间进行此自连接.
| 归档时间: | 
 | 
| 查看次数: | 1317 次 | 
| 最近记录: |