我有一个递归查询,如果 WHERE
子句包含常量,则执行速度非常快,但如果我用具有相同值的参数替换常量,则执行速度会非常慢。
查询 #1 - 使用常量
;WITH Hierarchy (Id, ParentId, Data, Depth)
AS
( SELECT Id, ParentId, NULL AS Data, 0 AS Depth
FROM Test
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
WHERE Id = 69
查询 #2 - 带参数
DECLARE @Id INT
SELECT @Id = 69
;WITH Hierarchy (Id, ParentId, Data, Depth)
AS
( SELECT Id, ParentId, NULL AS Data, 0 AS Depth
FROM Test
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
WHERE Id = @Id
如果表有 50,000 行,则带有常量的查询运行 10 毫秒,带有参数的查询运行 30 秒(慢 3,000 倍)。
不能选择将最后一个 WHERE
子句移动到递归的锚定定义,因为我想使用查询来创建 View (没有最后一个 WHERE
)。从 View 中进行的选择将具有 WHERE
子句 (WHERE Id = @Id
) - 由于 Entity Framework ,我需要这个,但那是另一个故事了。
任何人都可以建议一种方法来强制查询#2(带有参数)使用与查询#1(带有常量)相同的查询计划吗?
我已经尝试过使用索引,但这没有帮助。
如果有人愿意,我也可以发布表定义和一些示例数据。 我正在使用 SQL 2008 R2。
提前感谢您的帮助!
执行计划 - 查询 #1 - 具有常量
执行计划 - 查询 #2 - 带参数
最佳答案
正如 Martin 在该问题下的评论中所建议的,问题是 SQL Server 没有正确下推 WHERE 子句中的谓词 - 请参阅他评论中的链接。
我最终创建了一个用户定义的表值函数,并将其与 CROSS APPLY 运算符一起使用来创建 View 。
让我们看看解决方案本身。
用户定义的表值函数
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
)
查看
CREATE VIEW [dbo].[TestView]
AS
SELECT t.Id, t.ParentId, f.Data, f.Depth
FROM
Test AS t
CROSS APPLY TestFunction(Id) as f
常量查询
SELECT * FROM TestView WHERE Id = 69
带参数查询
DECLARE @Id INT
SELECT @Id = 69
SELECT * FROM TestView WHERE Id = @Id
带有参数的查询的执行速度基本上与带有常量的查询一样快。
谢谢马丁和其他人!
关于sql - 如果在 WHERE 子句中用参数(具有相同值)替换常量,为什么查询会急剧减慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4226035/