I have a recursive query which executes very fast if the WHERE
clause contains a constant but becomes very slow if I replace the constant with a parameter havin
As Martin suggested in a comment under the question, the problem is that SQL server does not push down properly the predicate from the WHERE clause - see the link in his comment.
I ended up with creating a user defined table-valued function and use it with the CROSS APPLY operator for creating the view.
Let's see the solution itself.
User Defined Table-valued Function
CREATE FUNCTION [dbo].[TestFunction] (@Id INT)
RETURNS TABLE
AS
RETURN
(
WITH
Hierarchy (Id, ParentId, Data, Depth)
AS(
SELECT Id, ParentId, NULL AS Data, 0 AS Depth FROM Test Where Id = @Id
UNION ALL
SELECT h.Id, t.ParentId, COALESCE(h.Data, t.Data), Depth + 1 AS Depth
FROM Hierarchy h
INNER JOIN Test t ON t.Id = h.ParentId
)
SELECT * FROM Hierarchy
)
View
CREATE VIEW [dbo].[TestView]
AS
SELECT t.Id, t.ParentId, f.Data, f.Depth
FROM
Test AS t
CROSS APPLY TestFunction(Id) as f
Query with constant
SELECT * FROM TestView WHERE Id = 69
Query with parameter
DECLARE @Id INT
SELECT @Id = 69
SELECT * FROM TestView WHERE Id = @Id
The query with the parmater executes basically as fast as the query with the constant.
Thank You Martin and for the others as well!
For your second Query try using the OPTIMIZE FOR or OPTION(RECOMPILE) query hint to see if that forces it to recomplile based on the provided parameter value.
You should use a plan guide to freeze the plan you want.
This could be the worse suggestion ever, but have you considered creating a sproc to create your query as a string and execute it using sp_executesql?
I know nothing about the caching behaviour of SQL executed by sp_executesql, it was just the first thing to pop into my head.