【问题标题】:SQL Server query plan generation optimizationSQL Server 查询计划生成优化
【发布时间】:2013-06-10 12:04:52
【问题描述】:

我有一个相当复杂的视图,它的定义中有大约 100 个子查询。

简单的语句如:

SELECT * FROM MyView

生成计划并执行查询耗时 2 秒。计划缓存后的后续选择耗时不到 1 毫秒。

如果我只有几个查询,这种情况会很好 - 性能只有一次是可以接受的。问题是我们的 ORM 使用 CTE 生成带有参数的分页查询。 更改参数值(页面)会导致查询计划重新计算 - 在这种情况下,不幸的是这需要大约 4 秒!

让我们添加过滤、排序,你就会明白会发生什么......

我可以做些什么来减少查询计划的创建时间或减少它们或以任何其他方式优化它?

@MartinSmith "SQL Server 不会为每个参数值生成计划,除非文本发生了某种变化"

我有一个这样的查询(我在这里放了星星而不是 120 多个字段列表):

DECLARE @low int = 20;
DECLARE @high int = 300;

WITH __actualSet
AS (
SELECT *
    ,ROW_NUMBER() OVER (
        ORDER BY CURRENT_TIMESTAMP
        ) AS __rowcnt
FROM (
    SELECT TOP 5000 *
    FROM [dbo].[Project] [LPA_L1]
    ORDER BY [LPA_L1].[CreatedOn] ASC
    ) AS _tmpSet
)
SELECT *
FROM __actualSet
WHERE [__rowcnt] > @low
AND [__rowcnt] <= @high
ORDER BY [__rowcnt] ASC

我第一次运行这个查询 ~4s。第二次~1ms。当我更改参数值时 - 再次 4s。也许我在这里误解了一些东西?

【问题讨论】:

  • 重写视图不使用 100 个子查询?虽然如果唯一改变的是 @parameter 值,这无论如何都不会导致重新编译。
  • 我不能重写视图不使用 100 个子查询,但是我会尝试使用投影来减少每次查询的列数。这工作基本相同,但仍然为每个参数值生成执行计划是疯狂的..
  • SQL Server 不会为每个参数值生成计划,除非文本发生了某种变化。
  • 您的 ORM 是否真的像您发布的代码一样生成查询?那使用变量而不是参数。如果发送到服务器的实际文本包括文本DECLARE @low int = 20;DECLARE @high int = 300; 后跟 SQL,那么是的,这将导致编译新计划。 ORDER BY CURRENT_TIMESTAMP 不保证做任何确定性的事情。
  • 感谢您的回答!我相信我的 ORM 会生成参数,但我已经在 SSMS 中的变量上对此进行了测试。我不知道这很重要。更重要的是我没有注意到这个ORDER BY CURRENT_TIMESTAMP 片段 - 哈哈!

标签: sql sql-server sql-server-2008-r2 query-performance


【解决方案1】:

要在 SSMS 中测试并为不同的值重用相同的计划,您需要参数化查询并使用 sp_executesql 执行它

DECLARE @low int = 20;
DECLARE @high int = 300;

EXEC sp_executesql N'
WITH __actualSet
AS (
SELECT *
    ,ROW_NUMBER() OVER (
        ORDER BY CURRENT_TIMESTAMP
        ) AS __rowcnt
FROM (
    SELECT TOP 5000 *
    FROM [dbo].[Project] [LPA_L1]
    ORDER BY [LPA_L1].[CreatedOn] ASC
    ) AS _tmpSet
)
SELECT *
FROM __actualSet
WHERE [__rowcnt] > @low
AND [__rowcnt] <= @high
ORDER BY [__rowcnt] ASC

', N'@low INT, @high INT', @low = @low, @high = @high

【讨论】:

  • 谢谢。这就像一个魅力!任何参数值都小于 1ms!
猜你喜欢
  • 2019-10-20
  • 1970-01-01
  • 2020-08-02
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 2016-06-08
相关资源
最近更新 更多