我有一个查询,最初运行时大约需要 9 秒才能返回,随后重新运行大约需要 4 秒。在阅读完这篇文章后,我相信这是计划缓存的一种表现(尽管我可能是错的)。我正在尝试优化此查询,而这种效果使这变得非常困难。
我对这是一个计划缓存问题的分析是正确的还是有其他选择?如果是这样,有没有办法在本地禁用此缓存(即:对于一个查询,而不是对于服务器)。
最后,选项(重新编译)如何适合这个讨论。
顺便说一句,我正在使用 SQL Server 2008,
我有一个查询,最初运行时大约需要 9 秒才能返回,随后重新运行大约需要 4 秒。在阅读完这篇文章后,我相信这是计划缓存的一种表现(尽管我可能是错的)。我正在尝试优化此查询,而这种效果使这变得非常困难。
我对这是一个计划缓存问题的分析是正确的还是有其他选择?如果是这样,有没有办法在本地禁用此缓存(即:对于一个查询,而不是对于服务器)。
最后,选项(重新编译)如何适合这个讨论。
顺便说一句,我正在使用 SQL Server 2008,
您可以使用“FREEPROCCACHE”清除计划缓存
有关如何从缓存中清除特定计划的示例,请参阅此 MSDN 页面。
也就是说,除非它是一个非常长的 SQL 语句,否则编译计划不会花费 4 秒,因此很可能是数据缓存导致您的查询在第一次执行后运行得更快。
罪魁祸首可能不是计划缓存,而是数据缓存。有两种方法可以解决这个问题。在开发服务器上,您可以运行
DROPCLEANBUFFERS
以清除数据缓存。您还应该使用查询计划和统计信息来进行优化。在这种情况下,您可以
SET STATISTICS IO On
专注于逻辑读取而不是物理读取。如果您在清除数据缓存后运行两次查询,您将看到物理读取急剧下降,但逻辑读取将保持不变。
`OPTION RECOMPILE`
只会影响计划缓存,并且只会在查询计划本身由于传入不同参数而发生变化的情况下产生影响,例如当结果集的大小发生巨大变化时。
减少逻辑读取?一般来说,会想到索引和覆盖索引。如果您查看执行计划,SQL Server 可能会在认为需要索引时建议它们。它实际上会为您提供适当的创建索引语法(尽管新索引并不总是有帮助)。同样在实际执行计划中,如果返回的行数与预期的行数大不相同,您可能需要查看统计信息。SQL 服务器维护索引列的统计信息,但如果自动统计未打开,那么如果 where 语句包含未索引的列,那么您可能希望为其生成统计信息(或对其进行索引或打开自动统计信息)。
这里有很多因素在起作用,但是在进行查询优化时,一种解决计划/数据缓存、数据库上的其他负载等影响的方法是专注于逻辑读取。这是需要完成的读取次数 - 对于给定的运行,它们是否来自缓存并不相关。
例子:
USE AdventureWorks2012;
GO
SET STATISTICS IO ON;
GO
SELECT *
FROM Production.ProductCostHistory
WHERE StandardCost < 500.00;
GO
SET STATISTICS IO OFF;
GO
结果:
Table 'ProductCostHistory'. Scan count 1, logical reads 5, physical
reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0,
lob read-ahead reads 0.
调整查询时,请专注于使逻辑读取尽可能低。