sql - 如果在 WHERE 子句中用参数(具有相同值)替换常量,为什么查询会急剧减慢?

标签 sql sql-server-2008 where-clause

我有一个递归查询,如果 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 - 具有常量

alt text

执行计划 - 查询 #2 - 带参数

alt text

最佳答案

正如 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/

相关文章:

sql - 带有 GROUP BY 的 3 个 SELECT 语句的平均值

sql - 带条件搜索字符串

sql - 处理 Bit 数据类型的数据仓库

sql - 如何获取不不同的值(计数 > 1)

sql - postgresql bug,查询找不到具有完全相同字符串的行

ruby-on-rails - Rails 更新 4.1.0 后,next 方法 (Class.first) 不起作用

sql - 在部分 CHAR 列上创建索引

sql - 如何引用刚刚插入的值(在 TRIGGER 语句中)?

sql-server - 将 varbinary 数据插入 SQL Server 数据库

mysql - sql select where子句问题