Example:
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;
If you run previous script in SSMS (press Ctrl+M
-> Actual Execution Plan) then you will get this execution plan for the last query:
In this case, the CTE is executed one time for crt
alias and five (!) times for prev
alias, once for every row from crt
.
So, the answer for this question
Does WITH statement execute once per query or once per row?
is both
: once per query (crt
) and once per row (prev
: once for every for from crt
).
To optimize this query, for the start,
1) You can try to store the results from CTE (MyCTE
or Query
) into a table variable or a temp table
2) Define the primary key of this table as been the join colum(s),
3) Rewrite the final query to use this table variable or temp table.
Off course, you can try to rewrite the final query without this self join between CTE.