Async Statistics Updates: Stopping Queries From Stalling

A query that normally returns in a blink sometimes waits through a statistics refresh. Async statistics updates let compilation proceed with the existing statistic while SQL Server refreshes it in the background. That avoids one stall, but it changes which estimate the first query uses.

A roadside farm stall open for trade while a red crate of tomatoes is added at the back.

Identify the Synchronous Stall

With the default synchronous setting, an optimizer that needs stale statistics waits for the update before compiling the statement. On a large table, sampling and metadata work can turn a short query into a long one. SQL Server 2019 and later expose WAIT_ON_SYNC_STATISTICS_REFRESH to make that wait visible. A wait snapshot only says time accumulated; capture the active request and a before-and-after interval when the complaint occurs.

SELECT session_id, status, wait_type, wait_time,
       blocking_session_id, command
FROM sys.dm_exec_requests
WHERE wait_type = N'WAIT_ON_SYNC_STATISTICS_REFRESH';

If the query returns no rows, the stall is not active now. Check Query Store duration patterns, statistics update times, and a controlled reproduction. I do not enable a database option because one wait appeared in a historical top-ten list. What query, statistic, and data change line up with the spike?

Capture the plan for the affected statement and note the statistics named in its optimizer statistics usage section when available. That narrows the search to objects the optimizer actually consulted. A table can hold dozens of statistics, and updating the wrong one proves little. Compare the slow call time with the last update timestamp. If the first call after a load is slow and later calls are quick, the pattern supports a synchronous refresh. If every call is slow, look beyond the refresh wait.

Check the Options Behind Async Statistics Updates

AUTO_UPDATE_STATISTICS must be on for automatic refreshes. AUTO_UPDATE_STATISTICS_ASYNC controls whether qualifying refreshes are asynchronous. Read both current values before changing anything. The asynchronous option is per database, so two databases on one instance can behave differently. The query below also reports the database name so a copied screenshot retains its context.

SELECT name, is_auto_update_stats_on,
       is_auto_update_stats_async_on
FROM sys.databases
WHERE database_id = DB_ID();

If automatic updates are off entirely, turning on the async option alone does not create a useful update process. Also inspect the particular statistic with sys.dm_db_stats_properties. Its last update, sampled rows, and modification counter help explain the optimizer's decision. A large counter does not mean every query suffers, but it identifies a candidate worth matching to the plan.

Enable Async Statistics Updates After a Workload Test

The database option is straightforward. The effect is not. The first compilation can use the old statistic and start a background update; later compilations can use the fresh one. For a highly skewed table, that first plan can be poor. Test representative parameter values and record both the first run and the later runs before declaring a win.

ALTER DATABASE [YourDatabase]
SET AUTO_UPDATE_STATISTICS_ASYNC ON;

Replace the name with the confirmed database. This is a real configuration change. Apply it through the normal change path, not in response to one chart. Keep a rollback command in the runbook, and compare Query Store plans and duration before and after. I favor this option for frequent short queries where a rare compilation stall hurts more than one compile with an older histogram.

Wait for the refresh or compile now: a diagram about the async statistics updates

Keep Async Statistics Updates From Blocking Compiles

An asynchronous refresh still needs to publish updated statistics metadata. On a busy system, that can require a schema modification lock and block other compilations. SQL Server 2022 and later offer ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY. The background worker waits in a low-priority queue for that lock. If it cannot get the lock within the internal timeout, the refresh is abandoned and can be retried by a later trigger or manual update.

ALTER DATABASE SCOPED CONFIGURATION
SET ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY = ON;
SELECT name, value
FROM sys.database_scoped_configurations
WHERE name = N'ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY';

Run this only on a version that supports the option. It is not a switch available on SQL Server 2019. Check that the async database option is on as well. A setting named low priority is not a substitute for watching whether updates finish. Monitor update timestamps and compilation waits after the change.

Keep Synchronous Updates Where the First Plan Matters

A nightly report that compiles once after a large load can benefit from fresh statistics before it starts. The same is true for a query whose old histogram is badly wrong for the new data. In those cases, synchronous refresh or an explicit planned UPDATE STATISTICS after the load can be more predictable than background work. The right choice depends on the workload, not the table's size alone.

A targeted maintenance step can update the important statistic at a known point, before users arrive. It avoids making an unlucky user query pay the refresh cost. Do not update every statistic after every load without measuring the maintenance time and plan churn. The aim is to put necessary work in a controlled window, not to move a surprise stall to another hour.

For volatile tables, ask how quickly the distribution changes. A statistic updated at midnight can already be misleading by noon. Asynchronous mode can leave the first caller with that older picture while the refresh runs. If a bad first plan is cached and reused, the apparent stall disappears but the workload remains slow. Check whether later compilations actually adopt the new statistic. A scheduled targeted update, plus a controlled recompile of the affected statement when needed, can be clearer than relying on timing alone.

Verify the Stalls Actually Stopped

Compare interval deltas for WAIT_ON_SYNC_STATISTICS_REFRESH, Query Store duration percentiles for the affected query, plan changes, and the statistic's last update time. Check for new blocking around asynchronous metadata publication. A lower wait total with worse query plans is not a win. A plan can be quick to compile and slow to run.

I save a before-and-after case with the query ID, statistic name, data-change pattern, and option values. If the query still spikes, inspect parameter sensitivity, blocking, I/O, and application timeouts. Statistics are a plausible culprit only when the evidence connects them to the delay. SQL Server has many ways to be slow; one wait name should not get all the credit.

Related reading on this blog: How to Enable Auto Update Statistics and Auto Create Statistics with T-SQL: Interview Question of the Week #108 and When Auto Update Statistics Is Not Enough.

Before and after you switch to async: a checklist on the async statistics updates

An async statistics update is not free speed, it is a trade between compile delay and an older estimate.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

SQL Performance, SQL Server, SQL Statistics
Previous Post
Consulting Wrap Up – What Next and How to Get Started
Next Post
SQL SERVER – A Brief History of Deadlock and Modern Approach of Resolution

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.