UPDATE STATISTICS: примеры (SQL)

Полное руководство по обновлению статистики в SQL Server
Раздел: Функции манипулирования статистиками, Статистика
UPDATE STATISTICS: N/A

Функция UPDATE STATISTICS в MS SQL

Функция UPDATE STATISTICS в Microsoft SQL Server предназначена для обновления статистических данных по индексам и столбцам таблицы или индексированного представления. Эти данные используются оптимизатором запросов для оценки наиболее эффективного плана выполнения. Обновление статистики выполняется, когда данные в таблице были значительно изменены (добавлены, удалены, обновлены), что может сделать существующую статистику устаревшей и привести к снижению производительности запросов.

Основные аргументы команды:

  • table_or_indexed_view_name - имя таблицы или индексированного представления.
  • index_or_statistics_name - (опционально) имя конкретного индекса или статистики. Если не указано, обновляется статистика по всем индексам и столбцам таблицы.
  • WITH options - ключевые слова для настройки процесса обновления.

Часто используемые параметры WITH:

  • FULLSCAN - выполняет полное сканирование таблицы для сбора статистики. Наиболее точный, но ресурсоемкий метод.
  • SAMPLE number {PERCENT|ROWS} - обновляет статистику на основе выборки указанного процента строк или их количества.
  • RESAMPLE - обновляет статистику, используя ранее заданную выборку. Если выборка не задавалась, действует как FULLSCAN.
  • ALL | COLUMNS | INDEX - указывает, какую статистику обновлять: всю, только по столбцам или только по индексам.
  • NORECOMPUTE - отключает автоматическое обновление статистики для указанного объекта.
  • INCREMENTAL = {ON | OFF} - для секционированных таблиц указывает, обновлять ли статистику по секциям отдельно.

Возвращаемые значения: сама инструкция не возвращает результирующий набор. Ее выполнение приводит к обновлению системных таблиц, хранящих статистику, и может повлиять на планы выполнения последующих запросов.

Примеры использования UPDATE STATISTICS

Обновление всей статистики для таблицы с полным сканированием:

UPDATE STATISTICS Sales.SalesOrderDetail WITH FULLSCAN;
Команда выполнена успешно.

Обновление статистики для конкретного индекса с выборкой 30 процентов:

UPDATE STATISTICS Sales.SalesOrderDetail IX_SalesOrderDetail_ProductID WITH SAMPLE 30 PERCENT;
Команда выполнена успешно.

Обновление статистики только по столбцам с отключением автообновления:

UPDATE STATISTICS Sales.SalesOrderDetail WITH COLUMNS, NORECOMPUTE;
Команда выполнена успешно.

Обновление статистики для индексированного представления:

UPDATE STATISTICS dbo.vIndexedView WITH RESAMPLE;
Команда выполнена успешно.

Альтернативные методы в MS SQL

sp_updatestats - системная хранимая процедура. Выполняет UPDATE STATISTICS для всех пользовательских таблиц в базе данных. Удобна для массового обновления, но не позволяет тонко настраивать параметры для каждой таблицы.

EXEC sp_updatestats;

CREATE/ALTER INDEX ... WITH (STATISTICS_NORECOMPUTE = ON) - параметр при создании или изменении индекса, который отключает автоматическое обновление статистики для этого индекса. Полезен для статических таблиц, но требует ручного управления.

Автоматическое обновление статистики - функция SQL Server, включенная по умолчанию. Статистика обновляется автоматически при изменении более 20% строк (для таблиц больше 500 строк). Иногда это поведение требует отключения для очень больших таблиц.

Выбор метода: для планового обслуживания больших баз часто используют UPDATE STATISTICS с SAMPLE в рамках задач обслуживания. sp_updatestats подходит для быстрого обновления всей базы после массовой загрузки данных. Автоматическое обновление эффективно для динамических таблиц среднего размера.

Аналоги в других СУБД

PostgreSQL: команда ANALYZE. Выполняет сбор статистики для оптимизатора. Не имеет прямых аналогов параметров SAMPLE или FULLSCAN, но может быть запущена для конкретной таблицы.

ANALYZE sales.order_details;
ANALYZE

Oracle: используется пакет DBMS_STATS. Гораздо более гибкий, позволяет собирать статистику на уровне схемы, таблицы, индекса, с различными методами выборки.

EXEC DBMS_STATS.GATHER_TABLE_STATS('SH', 'SALES', estimate_percent => 15);
PL/SQL procedure successfully completed.

MySQL: команда ANALYZE TABLE. Обновляет статистику, хранящуюся для таблицы и индексов.

ANALYZE TABLE orders;
+-------------+---------+----------+----------+
| Table       | Op      | Msg_type | Msg_text |
+-------------+---------+----------+----------+
| test.orders | analyze | status   | OK       |
+-------------+---------+----------+----------+

SQLite: команда ANALYZE. Создает или обновляет внутреннюю таблицу sqlite_stat1 для хранения статистики. Может быть запущена для всей базы, конкретной таблицы или индекса.

ANALYZE main.products;

Основное отличие MS SQL - более детальный контроль над объемом сканирования (FULLSCAN/SAMPLE) и типом обновляемой статистики (ALL/COLUMNS/INDEX). В Oracle и PostgreSQL управление статистикой часто более комплексное и тесно интегрировано в процессы управления базой данных.

Типичные ошибки

Использование команды в транзакции с последующим откатом. UPDATE STATISTICS является физической операцией, ее эффект нельзя откатить с помощью ROLLBACK, если не использовать явное начало транзакции, но это нестандартно.

BEGIN TRANSACTION;
UPDATE STATISTICS dbo.LargeTable WITH FULLSCAN; -- Долгая операция
-- ... другие действия
ROLLBACK; -- Откат не вернет ресурсы, затраченные на сбор статистики

Блокировки. По умолчанию UPDATE STATISTICS использует совместимые блокировки, но может конфликтовать с длительными операциями изменения данных. Это может приводить к ожиданиям или блокировкам. Использование параметра WITH RESUMABLE может смягчить проблему для очень больших таблиц.

Чрезмерное использование FULLSCAN на больших таблицах. Может вызвать проблемы с производительностью и нагрузкой на ввод-вывод. Для больших таблиц рекомендуется использовать SAMPLE.

-- Потенциально проблемный запрос для таблицы в 1ТБ
UPDATE STATISTICS dbo.HugeTable WITH FULLSCAN;
Выполнение может занять многие часы и создать нагрузку на диск.

Обновление статистики для временной таблицы. Статистика по временным таблицам создается автоматически. Явное обновление возможно, но требует использования двухзначного префикса (например, #temp) и может быть неэффективным из-за короткого времени жизни таблицы.

Изменения в новых версиях

В SQL Server 2014 появился параметр INCREMENTAL для секционированных таблиц. Он позволяет обновлять статистику не для всей таблицы, а только для измененных секций, что значительно ускоряет процесс для больших секционированных таблиц.

Начиная с SQL Server 2016, автоматическое обновление статистики работает в фоновом режиме с использованием асинхронного обновления статистики. Это означает, что если запрос обнаружил устаревшую статистику, он использует старый план, а обновление статистики происходит в фоне для следующих запросов.

В SQL Server 2019 и более новых версиях улучшена логика для управления памятью при выполнении UPDATE STATISTICS, особенно при работе с таблицами, имеющими кластеризованный индекс columnstore.

Для Azure SQL Database и управляемых экземпляров постоянно вносятся оптимизации в фоновые процессы работы со статистикой, обеспечивая высокую производительность без необходимости частого ручного вмешательства.

Расширенные примеры

Использование UPDATE STATISTICS с просмотром результатов через системные представления. Можно проверить дату последнего обновления статистики.

Пример sql
-- Обновляем статистику
UPDATE STATISTICS Production.Product WITH SAMPLE 50 PERCENT;

-- Проверяем дату обновления
SELECT 
    name AS StatsName,
    STATS_DATE(object_id, stats_id) AS LastStatsUpdate
FROM sys.stats 
WHERE object_id = OBJECT_ID('Production.Product');
StatsName                     LastStatsUpdate
------------------------------ -----------------------
PK_Product_ProductID          2023-10-26 14:35:22.120
AK_Product_ProductNumber      2023-10-26 14:35:22.120
...                           ...

Обновление статистики для фильтрованного индекса. Статистика для фильтрованных индексов собирается только на основе строк, удовлетворяющих условию фильтра.

Пример sql
CREATE INDEX IX_ActiveProducts ON Production.Product (Name) WHERE DiscontinuedDate IS NULL;
-- Обновляем статистику именно для этого индекса
UPDATE STATISTICS Production.Product IX_ActiveProducts WITH FULLSCAN;

Комбинирование параметров: обновление инкрементальной статистики для секционированной таблицы с отключением автообновления.

Пример sql
UPDATE STATISTICS dbo.PartitionedSalesData 
WITH INCREMENTAL = ON, NORECOMPUTE, SAMPLE 10 PERCENT;

Использование RESAMPLE для наследования плотности выборки. Если для статистики ранее задавалась выборка в 5%, RESAMPLE повторит эту выборку.

Пример sql
-- Первоначальное создание статистики с выборкой
UPDATE STATISTICS dbo.BigTable (IDX_BigTable) WITH SAMPLE 5 PERCENT;
-- ... прошло время
-- Последующее обновление с той же плотностью выборки
UPDATE STATISTICS dbo.BigTable (IDX_BigTable) WITH RESAMPLE;

Принудительное обновление статистики, помеченной как устаревшая, через sys.dm_db_stats_properties.

Пример sql
DECLARE @stats_name NVARCHAR(128);
DECLARE @table_name NVARCHAR(128) = 'Sales.SalesOrderDetail';

DECLARE stats_cursor CURSOR FOR
SELECT s.name 
FROM sys.stats s 
CROSS APPLY sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
WHERE s.object_id = OBJECT_ID(@table_name)
    AND sp.modification_counter > sp.rows * 0.20 -- Более 20% изменений

OPEN stats_cursor;
FETCH NEXT FROM stats_cursor INTO @stats_name;
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC('UPDATE STATISTICS ' + @table_name + ' ' + @stats_name + ' WITH SAMPLE 30 PERCENT;');
    FETCH NEXT FROM stats_cursor INTO @stats_name;
END
CLOSE stats_cursor;
DEALLOCATE stats_cursor;

MS SQL UPDATE STATISTICS function comments

En
UPDATE STATISTICS Updates query optimization statistics on a table or indexed view