我正在运行一些测试来找出查询计划在更新统计信息后何时失效。我用于测试的机器是 SQL Server Developer 2016 SP1 CU7。
我在BrentOzar.com上找到了一篇关于如何跟踪重新编译的文章,但我从未获得重新编译。
Auto Update Statistics
并且Auto Create Statistics
都已启用
这是我的测试:
/* Create a table and put over 1k rows in it (to get past the 500 row stats threshold) */
CREATE TABLE dbo.MyTable (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, StringField VARCHAR(50));
GO
INSERT INTO dbo.MyTable(StringField)
SELECT 'Stuff' FROM sys.all_objects;
GO
/* Start a trace monitoring recompiles */
exec sp_BlitzTrace @Action='start', @TargetPath='c:\temp\', @SessionId=@@SPID, @TraceRecompiles=1;
GO
SELECT * FROM dbo.MyTable WHERE StringField = 'NoRecordsHere';
GO
/* Increment the row mod counters to encourage a stats update */
BEGIN TRAN
DELETE dbo.MyTable;
GO
ROLLBACK
GO
UPDATE STATISTICS dbo.MyTable WITH fullscan
GO
/* We don't strictly need to wait, but makes different executions easier to see: */
WAITFOR DELAY '00:00:10';
GO
SELECT * FROM dbo.MyTable WHERE StringField = 'NoRecordsHere';
GO
EXEC sp_BlitzTrace @Action='stop'
GO
EXEC sp_BlitzTrace @Action='read'
GO
UPDATE STATISTICS WITH FULLSCAN
据我了解,当您致电并且行已更改时,该计划应该会失效。或者我错过了什么?
您的原始示例代码不可重新运行(表创建不在那里,或行的数量)所以我重写了它以充实它并使其可重新运行。
问题是您的查询非常简单:统计信息是否更新并不重要,它会产生相同的计划。此调整将使您的 SELECT 查询绕过微不足道的优化:
再次尝试测试:
现在你得到了重新编译 - 请注意显示 recompile_cause = "Statistics changed" 的第三行
这是sp_BlitzCache(免责声明:我是该开源脚本的非常小的作者)显示琐碎计划警告的原因之一 - 您无法获得完全优化计划中的所有酷炫内容,例如缺少索引建议。
我当然不是说在您的查询中添加“WHERE 1 = (SELECT 1)”是个好主意——只是说在构建重现场景时,您必须注意琐碎的查询。要了解您的查询是否非常简单,请查看执行计划,右键单击根节点(如 SELECT),单击属性,然后查看优化级别。如果它说的是 Trivial,那么您就没有得到 Microsoft 那些人的全部天才。