I have a view that uses a recursive CTE to give me the list of descendants for any given record (SQL Server 2014):
CREATE VIEW descendants AS
WITH results AS (
SELECT tbl.id,
tbl.id AS ancestorId
FROM tbl
UNION ALL
SELECT tbl.id,
d.ancestorId
FROM tbl
INNER JOIN results AS d ON d.id = tbl.parentId
)
SELECT * FROM results;
This works beautifully. A query like this returns the matching record ID and all descendant record IDs very quickly:
SELECT * FROM descendants WHERE ancestorId = 22;
However, once I use a variable, execution time goes from 0.1 seconds to 10 seconds!
DECLARE @p int;
SET @p = 22;
SELECT * FROM descendants WHERE ancestorId = @p;
The plans are very different.
The fast result, using a literal value:
The slow result, using a variable with the same value:
The source of evilness appears to be the eager spool.
How can I avoid this? I can't think of many use cases where this would be an advantage to the query.
Edit: I've seen some similar questions, but they seem to focus on the Halloween problem, which is not in play here. Since it's a comment, not an answer, I'll mention that the OPTION(RECOMPILE)
suggestion works great and I'm looking into changing the "anchor" (I've forgotten this terminology since I first used a recursive CTE a long time ago and I need to go refresh my memory).