SQL Server 2000:为什么这个查询w /变量对w/o变量这么慢?

Bil*_*l D 1 sql t-sql sql-server sql-server-2000

我无法弄清楚为什么这个查询对于变量而言如此缓慢而没有它们.我读了一些我需要启用"动态参数"的地方,但我找不到在哪里这样做.

DECLARE
      @BeginDate AS DATETIME
     ,@EndDate AS DATETIME
SELECT
      @BeginDate = '2010-05-20'
     ,@EndDate = '2010-05-25'

-- Fix date range to include time values
SET @BeginDate = CONVERT(VARCHAR(10), ISNULL(@BeginDate, '01/01/1990'), 101) + ' 00:00'
SET @EndDate = CONVERT(VARCHAR(10), ISNULL(@EndDate, '12/31/2099'), 101) + ' 23:59'

SELECT
     *
FROM
    claim c
WHERE
    (c.Received_Date BETWEEN @BeginDate AND @EndDate) --this is much slower
    --(c.Received_Date BETWEEN '2010-05-20' AND '2010-05-25') --this is much faster
Run Code Online (Sandbox Code Playgroud)

gbn*_*gbn 7

什么数据类型是"c.Received_Date"?

如果它不是datetime,那么该列将转换为datetime,因为@ BeginDate/@ EndDate是datetime.这称为数据类型优先级.这包括列是否为smalldatetime(根据链接),因为datetime几乎具有最高优先级

对于常量,优化器将使用列数据类型

转换意味着没有索引可以在计划中使用,这是原因.

在查看查询计划后编辑

对于文字,SQL Server计算出搜索后跟书签查找是最好的,因为值是文字.

通常,书签查找是昂贵的(并且顺便说一下我们使用覆盖索引的一个原因)超过少数几行.

对于使用变量的查询,它采用了一般情况,因为如果值更改,则可以重用计划.一般情况是避免书签查找,在这种情况下,您有一个PK(聚簇索引)扫描

阅读更多关于为什么书签查找在Simple-talk上通常是一件坏事的原因

在这种情况下,您可以尝试使用索引提示强制它,但如果范围太宽则会非常慢.或者你可以删除SELECT *(反正的不良做法)并替换SELECT col1, col2 etc并使用覆盖索引