Statistics Maintenance

Automated stale statistics detection and update. Identifies statistics with high modification counts relative to table size and runs targeted UPDATE STATISTICS. Processes databases individually to avoid silent failures. All objects in the dbo schema in DBA_Utilities.

Replaces Ola Hallengren's IndexOptimize for statistics-only maintenance. Instead of updating everything on a schedule, it identifies genuinely stale statistics based on modification rates and table size, then updates only those.

Key proc: dbo.sp_StatisticsMaintenance

How It Works

The proc loops through each database individually and identifies stale statistics based on these criteria:

ConditionThresholdRationale
No modifications + old> 30 days since updateStats may be outdated even without changes
Has modifications + aging> 7 days since updateAllow batching rather than constant updates
Large tables with mods> 5% modification rateHigh-row tables need tighter thresholds
Small tables with mods> 20% modification rateSmall tables tolerate more churn

Exclusions: CDC schema, empty tables, system tables.

Parameters

ParameterDefaultDescription
@DatabaseNameNULLNULL = all user databases. Supports comma-delimited list and LIKE wildcards
@Run00 = display what would be updated (dry run). 1 = execute the updates
@StatisticsSampleNULLNULL = SQL Server default. 100 = FULLSCAN. 1–99.99 = sample percentage
@TableNameNULLNULL = all tables. Supports CSV with optional schema prefix (dbo.MyTable)
@DetailOutput00 = minimal output (database progress only). 1 = detailed results per statistic

Logging

Every update is logged to dbo.StatisticsUpdate:

ColumnDescription
Database, Schema, Table, StatisticNameIdentifies the specific statistic updated
LastUpdatedWhen the stat was last updated before this run
DaysSinceUpdateHow stale the stat was
ModificationCountNumber of row modifications since last update
RowCount, ModificationPctTable size and modification rate
OutcomeSuccess or Failure
RunGroups updates from a single execution

Log entries older than 30 days are automatically purged.

Usage

Basic

-- Dry run: see what would be updated (all databases)
EXEC dbo.sp_StatisticsMaintenance @Run = 0;

-- Execute updates on all databases
EXEC dbo.sp_StatisticsMaintenance @Run = 1;

-- Single database with verbose output
EXEC dbo.sp_StatisticsMaintenance
    @DatabaseName = 'MyDatabase',
    @Run = 1,
    @DetailOutput = 1;

Full Scan on Specific Table

EXEC dbo.sp_StatisticsMaintenance
    @DatabaseName = 'MyDatabase',
    @TableName = 'dbo.LargeTable',
    @StatisticsSample = 100,
    @Run = 1;

Wildcard Database Filter

EXEC dbo.sp_StatisticsMaintenance
    @DatabaseName = 'MyApp_%',
    @Run = 1;

Check the Log

-- Recent updates
SELECT * FROM dbo.StatisticsUpdate
WHERE UpdateDate > DATEADD(DAY, -1, GETDATE())
ORDER BY UpdateDate DESC;

-- Summary by run
SELECT Run, MIN(UpdateDate) AS RunDate,
       COUNT(*) AS StatsUpdated,
       SUM(CASE WHEN Outcome = 'Success' THEN 1 ELSE 0 END) AS Succeeded,
       SUM(CASE WHEN Outcome = 'Failure' THEN 1 ELSE 0 END) AS Failed
FROM dbo.StatisticsUpdate
GROUP BY Run
ORDER BY Run DESC;