patternsqlMinor
Quickest Method To Invalidate Statistics
Viewed 0 times
quickeststatisticsmethodinvalidate
Problem
I'm doing some testing on sync vs async auto statistics updates. I'd like to quickly invalidate all statistic objects (headers, density vectors, and histograms) to ensure that next time the statistic is used that it will be updated.
I'm trying to simulate an auto update of statistics, not an auto creation.
Ideally I don't want to change the row count so I've dismissed
I had looked at
Is there an quick, efficient way to do what I want to achieve that I haven't considered?
I'm testing on SQL Server 2016.
I'm trying to simulate an auto update of statistics, not an auto creation.
Ideally I don't want to change the row count so I've dismissed
INSERT/DELETE operations. Ideally, I don't want to change any data values either, I have considered using UPDATE statements but I'm thinking this could take too long on some of my larger tables.I had looked at
UPDATE STATISTICS WITH ROWCOUNT, PAGECOUNT but I don't think this is what I'm after. I was hoping there was maybe a trace flag or undocumented command that would invalidate statistics.Is there an quick, efficient way to do what I want to achieve that I haven't considered?
I'm testing on SQL Server 2016.
Solution
The most reliable sequence I can find to cause an automatic statistics update is:
-
Update statistics sampling zero rows
This results in an empty statistic object.
-
Update the target column(s) in a single row of the table
This increments the column modification counter. The combination of an empty statistics object and an incremented modification counter enables a special case statistics update (it simulates creating statistics on an empty table, then adding a row).
-
Run the query with
This causes an automatic update of detected stale statistics, even if a matching plan for the query is already present in cache. The resulting statistics update will subsequently cause an optimality-based recompilation for the original cached plan, if it is matched again.
Demo
Using a similar AdventureWorks query as used in jyao's answer, the following script puts everything above together:
Output
The
-
Update statistics sampling zero rows
This results in an empty statistic object.
-- Example
UPDATE STATISTICS
Person.[Address]
IX_Address_StateProvinceID
WITH SAMPLE 0 ROWS;-
Update the target column(s) in a single row of the table
This increments the column modification counter. The combination of an empty statistics object and an incremented modification counter enables a special case statistics update (it simulates creating statistics on an empty table, then adding a row).
-- Example
BEGIN TRANSACTION;
UPDATE TOP (1)
Person.[Address]
SET StateProvinceID = StateProvinceID;
ROLLBACK TRANSACTION;-
Run the query with
OPTION (RECOMPILE)This causes an automatic update of detected stale statistics, even if a matching plan for the query is already present in cache. The resulting statistics update will subsequently cause an optimality-based recompilation for the original cached plan, if it is matched again.
-- Example
SELECT
A.City,
A.AddressLine1,
A.AddressLine2
FROM Person.[Address] AS A
WHERE
1 = 1
AND A.StateProvinceID = 54
OPTION (RECOMPILE);Demo
Using a similar AdventureWorks query as used in jyao's answer, the following script puts everything above together:
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;
GOOutput
The
DBCC SHOW_STATISTICS results show the original statistics header, the empty header, and the desired updated header at the end of the process:Code Snippets
-- Example
UPDATE STATISTICS
Person.[Address]
IX_Address_StateProvinceID
WITH SAMPLE 0 ROWS;-- Example
BEGIN TRANSACTION;
UPDATE TOP (1)
Person.[Address]
SET StateProvinceID = StateProvinceID;
ROLLBACK TRANSACTION;-- Example
SELECT
A.City,
A.AddressLine1,
A.AddressLine2
FROM Person.[Address] AS A
WHERE
1 = 1
AND A.StateProvinceID = 54
OPTION (RECOMPILE);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;
GOContext
StackExchange Database Administrators Q#157696, answer score: 7
Revisions (0)
No revisions yet.