使统计数据无效的最快方法

Fza*_*Fza 5 sql-server statistics sql-server-2016

我正在对同步与异步自动统计更新进行一些测试。我想快速使所有统计对象(标题、密度向量和直方图)失效,以确保下次使用统计时会更新

我正在尝试模拟统计数据的自动更新,而不是自动创建。

理想情况下,我不想更改行数,因此我已取消INSERT/DELETE操作。理想情况下,我也不想更改任何数据值,我已经考虑使用UPDATE语句,但我认为这在我的一些较大的表上可能需要太长时间。

我已经看过了,UPDATE STATISTICS WITH ROWCOUNT, PAGECOUNT但我认为这不是我所追求的。我希望可能有一个跟踪标志或未记录的命令会使统计数据无效。

有没有一种快速有效的方法来完成我没有考虑过的我想要实现的目标?

我正在 SQL Server 2016 上进行测试。

Pau*_*ite 7

我能找到的导致自动统计更新的最可靠序列是:

  1. 更新对零行进行采样的统计信息
    这会导致一个空的统计信息对象。

    -- Example
    UPDATE STATISTICS 
        Person.[Address] 
        IX_Address_StateProvinceID 
        WITH SAMPLE 0 ROWS;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 更新表的单行中的目标列
    这会增加列修改计数器。一个空的统计对象和一个递增的修改计数器的组合可以实现一个特殊情况的统计更新(它模拟在一个空表上创建统计,然后添加一行)。

    -- Example
    BEGIN TRANSACTION;
        UPDATE TOP (1) 
            Person.[Address] 
        SET StateProvinceID = StateProvinceID;
    ROLLBACK TRANSACTION;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 运行查询OPTION (RECOMPILE)
    这会导致自动更新检测到的陈旧统计信息,即使查询的匹配计划已存在于缓存中。如果原始缓存计划再次匹配,则生成的统计信息更新随后将导致基于最优性的重新编译。

    -- Example
    SELECT
        A.City,
        A.AddressLine1,
        A.AddressLine2
    FROM Person.[Address] AS A
    WHERE
        1 = 1
        AND A.StateProvinceID = 54
    OPTION (RECOMPILE);
    
    Run Code Online (Sandbox Code Playgroud)

演示

使用jyao's answer 中使用的类似AdventureWorks查询,以下脚本将上述所有内容放在一起:

DBCC FREEPROCCACHE;
GO
-- Cache a plan for the query
GO
SELECT
    A.City,
    A.AddressLine1,
    A.AddressLine2
FROM Person.[Address] AS A
WHERE
    1 = 1
    AND A.StateProvinceID = 54;
GO
DBCC SHOW_STATISTICS 
(
    'Person.Address', 
    'IX_Address_StateProvinceID'
) WITH STAT_HEADER;
GO
-- Empty stats object
UPDATE STATISTICS 
    Person.[Address] 
    IX_Address_StateProvinceID 
    WITH SAMPLE 0 ROWS;
GO
-- Perform and rollback a single row update
BEGIN TRANSACTION;
    UPDATE TOP (1) 
        Person.[Address] 
    SET StateProvinceID = StateProvinceID;
ROLLBACK TRANSACTION;
GO
DBCC SHOW_STATISTICS 
(
    'Person.Address', 
    'IX_Address_StateProvinceID'
) WITH STAT_HEADER;
GO
-- Run the query again to trigger stats update
GO
SELECT
    A.City,
    A.AddressLine1,
    A.AddressLine2
FROM Person.[Address] AS A
WHERE
    1 = 1
    AND A.StateProvinceID = 54
OPTION (RECOMPILE);
GO
DBCC SHOW_STATISTICS 
(
    'Person.Address', 
    'IX_Address_StateProvinceID'
) WITH STAT_HEADER;
GO
Run Code Online (Sandbox Code Playgroud)

输出

DBCC SHOW_STATISTICS结果表明,该原始统计报头,空报头,并且在该过程结束时所期望的更新标头:

<code>DBCC SHOW_STATISTICS</code> 结果


jya*_*yao 5

不确定以下方法是否符合您的要求,我会说您可以尝试这样做:

update statistics <your_table_name> with sample 0 rows
Run Code Online (Sandbox Code Playgroud)

这实际上会清除统计信息中的所有信息(它们本身是 sql server 对象并且仍然存在,即不删除统计信息本身)

根据MSDN

我们建议不要指定 0 PERCENT 或 0 ROWS。当指定 0 PERCENT 或 ROWS 时,更新统计对象但不包含统计数据。

对我来说,清空你的统计数据可以被认为是使你的统计数据“无效”的一种方式。:-)

[更新]我对SQL2014做了一个快速测试如下:

use AdventureWorks2014
dbcc show_statistics ('person.address', 'IX_Address_StateProvinceID')
Run Code Online (Sandbox Code Playgroud)

我可以看到以下内容

原始数据

然后我可以运行以下命令

select city, addressline1, addressline2 from person.address where StateProvinceID = 54
Run Code Online (Sandbox Code Playgroud)

我会得到一个执行计划如下

带有统计信息的执行计划

现在我将执行以下操作

update statistics person.address  with sample 0 rows
dbcc show_statistics ('person.address', 'IX_Address_StateProvinceID')
Run Code Online (Sandbox Code Playgroud)

我会看到统计数据消失了。

stats_gone

现在如果我跑

dbcc freeproccache
dbcc dropcleanbuffers
select city, addressline1, addressline2 from person.address where StateProvinceID = 54
Run Code Online (Sandbox Code Playgroud)

我会得到一个不同的执行计划。

new_exec_plan