【问题标题】:Why SQL Server go slow when using variables?为什么 SQL Server 在使用变量时会变慢?
【发布时间】:2008-11-24 11:34:37
【问题描述】:

我有一个运行超快的 sql 查询,大约一秒钟,当不使用变量时,例如:

WHERE id BETWEEN 5461094 and 5461097

但是当我有的时候:

declare @firstId int
declare @lastId int

set @firstId = 5461094
set @lastId = 5461097

...
    WHERE id BETWEEN @firstId and @lastId

...查询运行得很慢,几分钟后才结束。为什么会这样?我需要使用变量。我可以做一些改进来避免这个性能问题吗?

【问题讨论】:

    标签: sql sql-server stored-procedures


    【解决方案1】:

    好的,

    1. 您是优化者,而查询计划是一个工具。
    2. 我会给你一个问题,你必须选择车辆。
    3. 图书馆的所有书籍都有序号

    我的查询是去图书馆,把 3 到 5 之间的所有书拿给我

    您会选择一辆合适、快速、便宜、高效且大到可以带回 3 本书的自行车。

    新查询。

    去图书馆,把@x 和@y 之间的所有书拿来。

    选择车辆。

    继续。

    就是这样。如果我要 1 和 Maxvalue 之间的书,你会选择自卸车吗?如果 x=3 和 y=5,那就太过分了。 SQL 必须在看到数字之前选择计划。

    【讨论】:

    • 更新存储过程并在末尾添加option recompile
    • 这很好地解释了微软做错了什么。现实生活:询问变量值,然后选择合适的车辆。
    【解决方案2】:

    这是因为当值被硬编码时,它可以在表中的数据上查找the statistics,并找出要运行的最佳查询。查看每个查询的执行计划。使用变量的时候一定是扫描的。

    如果范围总是很小,您可以使用索引提示来帮助解决此问题。

    【讨论】:

    • 在 Oracle 中,如果范围总是很小,一切都会好起来的。它将根据第一个变量选择计划。如果它总是很小,你总是很好。它是在极端之间摇摆不定的案例。我认为 SS 最近添加了类似偷看的东西……也许是 05 年或 08 年。
    【解决方案3】:

    有趣的是这段代码也会很快:

    DECLARE @sql VARCHAR(8000)
    
    SET @sql = 'SELECT * FROM table_x WHERE id BETWEEN ' + CAST(@firstId AS VARCHAR) + ' AND ' + CAST(@lastId AS VARCHAR)
    
    EXEC (@sql)
    

    (MSSQL 2000)

    【讨论】:

      【解决方案4】:

      如果这些变量是存储过程的输入变量,您可能会遇到参数嗅探问题。 http://omnibuzz-sql.blogspot.com/2006/11/parameter-sniffing-stored-procedures.html

      【讨论】:

        【解决方案5】:

        这个查询似乎与存储过程有关,它的执行计划将在第一次执行 proc 时被编译,然后再用于后续执行。

        编译计划对于 firstid 非常接近 lastid 的情况可能真的很糟糕,但是当值相距很远时它真的很好。

        尝试在您的存储过程中启用 WITH RECOMPILE 选项。如果它解决了问题,并且您对每次执行时都重新编译 proc 感到满意(您将受到性能影响),请将其留在那里。如果您仍然对性能不满意,请考虑重新构建 proc,这样它就不需要重新编译。

        【讨论】:

          【解决方案6】:

          ID 是否在索引中(例如主键)?如果没有,请尝试添加一个。

          另一件事可能是,在第一个(快速)实例中,查询的执行方式略有不同。我见过的最常见的事情是连接以低效的顺序完成。尝试重新排序连接,或将一些连接转换为子查询。如果您发布更多查询,我们可以提供进一步帮助。

          【讨论】:

            【解决方案7】:

            其实回答的很好,我只是在这里写一个解决方法,因为它对我有用:

            使用 SQL 创建存储过程

            WHERE id BETWEEN @firstId and @lastId
            

            然后使用参数@firstId 和@lastId 调用存储过程,它会加速。我仍然不是 100% 为什么它有效,但它有效。

            【讨论】:

              猜你喜欢
              • 2010-10-22
              • 1970-01-01
              • 2022-01-17
              • 2019-03-29
              • 2019-11-16
              • 2012-05-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多