【问题标题】:SQL Server 2000: Why is this query w/ variables so slow vs w/o variables?SQL Server 2000:为什么这个带变量的查询比不带变量的查询慢?
【发布时间】:2010-05-25 14:12:49
【问题描述】:

我不明白为什么这个查询在使用变量时会如此缓慢,而不是在没有变量的情况下。我阅读了一些我需要启用“动态参数”的地方,但我找不到在哪里执行此操作。

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

【问题讨论】:

  • 你在用什么运行它?存储过程?查询分析器?
  • 尝试在每次测试之前运行这两个命令(假设您没有在实时服务器上测试): DBCC FREEPROCCACHE 和 DBCC DROPCLEANBUFFERS 。它们有助于在比较查询时隐藏误导性的快速结果。
  • @William DiStefano:你能发布查询计划吗?
  • 我不知道我是否可以使用 SQL 2000 的查询分析器复制/粘贴它,但这里是一个似乎包含大部分执行计划的屏幕截图:imgur.com/HgqAK.jpg
  • @CodeByMoonlight - 使用“DBCC FREEPROCCACHE”或“DBCC DROPCLEANBUFFERS”后没有变化

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

“c.Received_Date”是什么数据类型?

如果不是日期时间,则该列将转换为日期时间,因为@BeginDate/@EndDate 是日期时间。这被称为data type precedence。这包括列是否为 smalldatetime(根据链接),因为 datetime 几乎具有最高优先级

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

转换意味着计划中不能使用索引查找,这就是原因。

查看查询计划后进行编辑

对于字面量,SQL Server 发现先查找后跟书签查找是最好的,因为值是字面量。

通常,书签查找成本很高(顺便说一句,我们使用覆盖索引的原因之一)不止几行。

对于使用变量的查询,它采用一般情况,因为如果值发生变化,它可以重用计划。一般情况是避免书签查找,在这种情况下,您需要进行 PK(聚集索引)扫描

Simple-talk

上阅读更多关于为什么书签查找通常是坏事

在这种情况下,您可以尝试使用索引提示来强制它,但如果范围太宽,它会非常慢。或者您可以删除SELECT *(无论如何都是不好的做法)并替换为SELECT col1, col2 etc并使用covering index

【讨论】:

  • @William,注意变量是日期时间,而常量只是日期。
  • c.Received_Date 列是日期时间。另外,我知道肯定存在某种设置问题,因为我可以在数据库中使用相同数据的不同服务器上运行完全相同的查询,并且它可以通过变量快速运行。
【解决方案2】:
SET STATISTICS IO ON
SET STATISTICS TIME ON

扫描次数和逻辑读取次数?

【讨论】:

    【解决方案3】:

    您已经提到,对不同服务器上的相同数据的相同查询运行速度很快。

    硬件是否相同,或者至少相当相似?

    • 处理器 - 相同数量?
    • 是否有处理器超线程?
    • 磁盘的物理布局是否相同(磁盘速度、数据、日志、tempdb 的单独主轴?)

    这种行为通常可以通过过时的统计数据看到。

    use dbfoo;
    go
    exec sp_updatestats
    go
    

    最后,比较每个框的 SQL 设置:

    exec sp_configure 'show advanced options', '1'
    go
    RECONFIGURE
    exec sp_configure;
    go
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 2012-08-19
      相关资源
      最近更新 更多