Создание и обновление статистики таблиц в выделенном пуле SQL
В этой статье приведены рекомендации и примеры создания и обновления статистики оптимизации запросов в таблицах в выделенном пуле SQL.
Для чего используется статистика?
Чем больше выделенному пулу SQL известно о ваших данных, тем быстрее он выполняет запросы к этим данным. После загрузки данных в выделенный пул SQL сбор статистики по данным является одной из наиболее важных вещей, которые можно сделать для оптимизации запросов.
Оптимизатор запросов выделенного пула SQL работает по принципу оценки стоимости. Он сравнивает стоимость разных планов запроса, а затем выбирает план с наименьшей стоимостью. В большинстве случаев он выбирает план, который выполняется быстрее.
Например, оптимизатор выбирает определенный план, если оценивается, что дата фильтрации запросов возвращает одну строку. Если оптимизатор оценивает, что выбранная дата возвращает миллион строк, он выбирает другой план.
Автоматическое создание статистики
Если параметр базы данных AUTO_CREATE_STATISTICS
включен, выделенный пул SQL анализирует входящие запросы пользователей для отсутствия статистики.
Если она отсутствует, оптимизатор запросов создает статистику по отдельным столбцам в предикате запроса или условии соединения, чтобы улучшить оценку кратности для плана запроса.
Примечание.
Автоматическое создание статистики в настоящее время включено по умолчанию.
Можно проверить, настроен ли AUTO_CREATE_STATISTICS
выделенный пул SQL, выполнив следующую команду T-SQL:
SELECT name, is_auto_create_stats_on
FROM sys.databases
Если выделенный пул SQL не AUTO_CREATE_STATISTICS
настроен, рекомендуется включить это свойство, выполнив следующую команду. Замените <your-datawarehouse-name>
именем выделенного пула SQL.
ALTER DATABASE <your-datawarehouse-name>
SET AUTO_CREATE_STATISTICS ON
Эти инструкции активируют автоматическое создание статистики:
SELECT
-
INSERT
...SELECT
-
CREATE TABLE AS SELECT
(CTAS) UPDATE
DELETE
-
EXPLAIN
При обнаружении соединения или наличия предиката
Примечание.
Автоматическое создание статистики не выполняется во временных или внешних таблицах.
Автоматическое создание статистики выполняется синхронно, поэтому вы можете немного снизить производительность запросов, если столбцы отсутствуют в статистике. Время создания статистики для одного столбца зависит от размера таблицы.
Чтобы избежать ощутимого замедления, убедитесь, что сначала создается статистика, выполняя рабочую нагрузку теста производительности перед профилированием системы.
Примечание.
Создание статистики регистрируется в журнале sys.dm_pdw_exec_requests в контексте другого пользователя.
При создании автоматической статистики они принимают форму: _WA_Sys_<8 digit column id in Hex>_<8 digit table id in Hex>
Созданную статистику можно просмотреть, запустив команду DBCC SHOW_STATISTICS:
DBCC SHOW_STATISTICS (<table_name>, <target>)
Имя table_name
таблицы, содержащей статистику для отображения. Эта таблица не может быть внешней таблицей. Аргумент target — имя целевого индекса, статистики или столбца, для которого нужно отобразить статистические данные.
Обновите статистику
Лучше всего обновлять статистику в столбцах дат каждый день, когда добавляются новые даты. При каждой загрузке строк в выделенный пул SQL, добавляются даты новых загрузок или транзакций. Эти дополнения изменяют распределение данных и делают статистику устаревшей.
Статистика по столбцу "Страна или регион" в таблице клиента может никогда не обновляться, т. к. распределение значений обычно не меняется. Если предположить, что распределение между клиентами постоянно, добавление новых строк в вариант таблицы не изменит распределение данных.
Но если выделенный пул SQL содержит только одну страну или регион и появляются данные из новой страны или региона, что означает поступление данных из нескольких стран, статистику по столбцу "Страна или регион" необходимо будет обновить.
Ниже приведены рекомендации по обновлению статистики:
Атрибут статистики | Рекомендация |
---|---|
Частота обновления статистики | Консервативная: ежедневно После загрузки или преобразования данных |
Выборка | Если менее 1 млрд строк, используйте выборку по умолчанию (20 %).
Если строк более 1 000 000 000, используйте выборку в 2 %. |
Один из первых вопросов, которые следует задать при устранении неполадок с запросом: "Обновлена ли статистика?"
Этот вопрос нельзя ответить на возраст данных. Актуальный объект статистики может быть старым, если исходные данные существенно не менялись. Если количество строк или распределение значений для столбца значительно изменяется, то в этот момент необходимо обновить статистику.
Динамическое административное представление не определяет, изменились ли данные в таблице с момента последнего обновления статистики. Следующие два запроса могут помочь определить, устарела ли статистика.
Запрос 1. Найдите разницу между числом строк из статистики (
stats_row_count
) и фактическим числом строк (actual_row_count
).select objIdsWithStats.[object_id], actualRowCounts.[schema], actualRowCounts.logical_table_name, statsRowCounts.stats_row_count, actualRowCounts.actual_row_count, row_count_difference = CASE WHEN actualRowCounts.actual_row_count >= statsRowCounts.stats_row_count THEN actualRowCounts.actual_row_count - statsRowCounts.stats_row_count ELSE statsRowCounts.stats_row_count - actualRowCounts.actual_row_count END, percent_deviation_from_actual = CASE WHEN actualRowCounts.actual_row_count = 0 THEN statsRowCounts.stats_row_count WHEN statsRowCounts.stats_row_count = 0 THEN actualRowCounts.actual_row_count WHEN actualRowCounts.actual_row_count >= statsRowCounts.stats_row_count THEN CONVERT(NUMERIC(18, 0), CONVERT(NUMERIC(18, 2), (actualRowCounts.actual_row_count - statsRowCounts.stats_row_count)) / CONVERT(NUMERIC(18, 2), actualRowCounts.actual_row_count) * 100) ELSE CONVERT(NUMERIC(18, 0), CONVERT(NUMERIC(18, 2), (statsRowCounts.stats_row_count - actualRowCounts.actual_row_count)) / CONVERT(NUMERIC(18, 2), actualRowCounts.actual_row_count) * 100) END from ( select distinct object_id from sys.stats where stats_id > 1 ) objIdsWithStats left join ( select object_id, sum(rows) as stats_row_count from sys.partitions group by object_id ) statsRowCounts on objIdsWithStats.object_id = statsRowCounts.object_id left join ( SELECT sm.name [schema] , tb.name logical_table_name , tb.object_id object_id , SUM(rg.row_count) actual_row_count FROM sys.schemas sm INNER JOIN sys.tables tb ON sm.schema_id = tb.schema_id INNER JOIN sys.pdw_table_mappings mp ON tb.object_id = mp.object_id INNER JOIN sys.pdw_nodes_tables nt ON nt.name = mp.physical_name INNER JOIN sys.dm_pdw_nodes_db_partition_stats rg ON rg.object_id = nt.object_id AND rg.pdw_node_id = nt.pdw_node_id AND rg.distribution_id = nt.distribution_id WHERE rg.index_id = 1 GROUP BY sm.name, tb.name, tb.object_id ) actualRowCounts on objIdsWithStats.object_id = actualRowCounts.object_id
Запрос 2. Найдите возраст статистики, проверив время последнего обновления статистики в каждой таблице.
Примечание.
Если в столбце есть существенное изменение распределения значений, следует обновить статистику независимо от последнего обновления.
SELECT sm.[name] AS [schema_name], tb.[name] AS [table_name], co.[name] AS [stats_column_name], st.[name] AS [stats_name], STATS_DATE(st.[object_id],st.[stats_id]) AS [stats_last_updated_date] FROM sys.objects ob JOIN sys.stats st ON ob.[object_id] = st.[object_id] JOIN sys.stats_columns sc ON st.[stats_id] = sc.[stats_id] AND st.[object_id] = sc.[object_id] JOIN sys.columns co ON sc.[column_id] = co.[column_id] AND sc.[object_id] = co.[object_id] JOIN sys.types ty ON co.[user_type_id] = ty.[user_type_id] JOIN sys.tables tb ON co.[object_id] = tb.[object_id] JOIN sys.schemas sm ON tb.[schema_id] = sm.[schema_id] WHERE st.[user_created] = 1;
Например, для столбцов "Дата" в выделенном пуле SQL обычно требуется часто обновлять статистику. При каждой загрузке строк в выделенный пул SQL, добавляются даты новых загрузок или транзакций. Эти дополнения изменяют распределение данных и делают статистику устаревшей.
И наоборот, статистика по столбцу пола в таблице клиентов может никогда не обновляться. Если предположить, что распределение между клиентами постоянно, добавление новых строк в вариант таблицы не изменит распределение данных.
Если выделенный пул SQL содержит сведения только о клиентах одного пола, а новые требования предписывают гендерные различия, то вам необходимо обновить статистику по столбцу "Пол".
Дополнительные сведения можно получить в общем руководстве по статистике.
Реализация управления статистикой
Часто рекомендуется расширить процесс загрузки данных, чтобы гарантировать, что статистика обновляется в конце нагрузки, чтобы избежать или свести к минимуму блокировку или несоответствие ресурсов между параллельными запросами.
Загрузка данных заключается в том, что таблицы чаще всего изменяют их размер или распределение значений. Именно при загрузке данных логично реализовать некоторые процессы управления.
Ниже приведены основные принципы обновления статистики.
- Убедитесь, что для каждой загружаемой таблицы обновляется по крайней мере один объект статистики. Тогда при обновлении статистики обновляется информация о размере таблицы (число строк и страниц).
- Сосредоточьтесь на столбцах, участвующих в предложениях JOIN, GROUP BY, ORDER BY и DISTINCT.
- Рекомендуется чаще обновлять ключевые столбцы по возрастанию, такие как даты транзакций, так как эти значения не включены в гистограмму статистики.
- Рекомендуется реже обновлять столбцы со статическим распределением.
- Помните, что каждый объект статистики обновляется последовательно. Просто реализовать
UPDATE STATISTICS <TABLE_NAME>
может быть не идеальным решением, особенно для обширных таблиц с большим количеством объектов статистики.
Дополнительные сведения см. в разделе об оценке кратности.
Примеры: создание статистики
Эти примеры показывают, как использовать различные параметры для создания статистики. Параметры, используемые для каждого столбца, зависят от характеристик данных и способа использования столбца в запросах.
Создание одностолбцовой статистики с параметрами по умолчанию
Чтобы создать одностолбцовую статистику, достаточно указать имя объекта статистики и имя столбца.
В этом синтаксисе все параметры используются по умолчанию. По умолчанию при создании статистики используется выборка 20 процентов таблицы.
CREATE STATISTICS [statistics_name] ON [schema_name].[table_name]([column_name]);
Например:
CREATE STATISTICS col1_stats ON dbo.table1 (col1);
Создание одностолбцовой статистики путем проверки всех строк
В большинстве случаев достаточно использовать частоту выборки по умолчанию, 20 процентов. Однако вы можете настроить частоту выборки.
Для выборки всей таблицы используйте следующий синтаксис:
CREATE STATISTICS [statistics_name] ON [schema_name].[table_name]([column_name]) WITH FULLSCAN;
Например:
CREATE STATISTICS col1_stats ON dbo.table1 (col1) WITH FULLSCAN;
Создание одностолбцовой статистики с указанием размера выборки
В качестве альтернативы можно указать размер выборки в процентах:
CREATE STATISTICS col1_stats ON dbo.table1 (col1) WITH SAMPLE = 50 PERCENT;
Создание одностолбцовой статистики только для некоторых строк
Можно также создать статистику для части строк в таблице. Это называется отфильтрованной статистикой.
Например, отфильтрованную статистику можно использовать при планировании запроса определенной секции большой секционированной таблицы. Создавая статистику только по значениям секций, точность статистики улучшается, что повышает производительность запросов.
Этот пример создает статистику по диапазону значений. Значения можно легко определить для сопоставления с диапазоном значений в секции.
CREATE STATISTICS stats_col1 ON table1(col1) WHERE col1 > '2000101' AND col1 < '20001231';
Примечание.
Чтобы оптимизатор запросов рассмотрел возможность использования отфильтрованной статистики, когда выбирает план распределенного запроса, запрос должен быть в пределах определения объекта статистики. Если взять приведенный выше пример, предложение WHERE запроса должно указать значения col1 от 2000101 до 20001231.
Создание одностолбцовой статистики со всеми параметрами
Можно также комбинировать параметры. В приведенном ниже примере создается отфильтрованный объект статистики с настраиваемым размером выборки:
CREATE STATISTICS stats_col1 ON table1 (col1) WHERE col1 > '2000101' AND col1 < '20001231' WITH SAMPLE = 50 PERCENT;
Полные справочные сведения см. в статье CREATE STATISTICS (Transact-SQL).
Создание многостолбцовой статистики
Для создания объекта статистики с несколькими столбцами используйте предыдущие примеры, но укажите больше столбцов.
Примечание.
Гистограмма, используемая для оценки количества строк в результатах запроса, доступна только для первого столбца, указанного в определении объекта статистики.
В этом примере гистограмма включена product_category
. Статистические данные между столбцами вычисляются и product_category
product_sub_category
:
CREATE STATISTICS stats_2cols ON table1 (product_category, product_sub_category) WHERE product_category > '2000101' AND product_category < '20001231' WITH SAMPLE = 50 PERCENT;
Так как существует корреляция между product_category
и product_sub_category
, объект статистики с несколькими столбцами может быть полезен, если эти столбцы доступны одновременно.
Создание статистики для всех столбцов в таблице
Одним из способов создания статистики является выдача CREATE STATISTICS
команд после создания таблицы:
CREATE TABLE dbo.table1
(
col1 int
, col2 int
, col3 int
)
WITH
(
CLUSTERED COLUMNSTORE INDEX
)
;
CREATE STATISTICS stats_col1 on dbo.table1 (col1);
CREATE STATISTICS stats_col2 on dbo.table2 (col2);
CREATE STATISTICS stats_col3 on dbo.table3 (col3);
Использование хранимой процедуры для создания статистики по всем столбцам в пуле SQL
Выделенный пул SQL не имеет системной хранимой процедуры sp_create_stats
в SQL Server. Эта хранимая процедура создает объект одностолбцовой статистики для каждого столбца в пуле SQL, для которого статистики еще нет.
В следующем примере показано, как приступить к работе с проектом пула SQL. Вы можете адаптировать код в соответствии со своими нуждами.
CREATE PROCEDURE [dbo].[prc_sqldw_create_stats]
( @create_type tinyint -- 1 default 2 Fullscan 3 Sample
, @sample_pct tinyint
)
AS
IF @create_type IS NULL
BEGIN
SET @create_type = 1;
END;
IF @create_type NOT IN (1,2,3)
BEGIN
THROW 151000,'Invalid value for @stats_type parameter. Valid range 1 (default), 2 (fullscan) or 3 (sample).',1;
END;
IF @sample_pct IS NULL
BEGIN;
SET @sample_pct = 20;
END;
IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN;
DROP TABLE #stats_ddl;
END;
CREATE TABLE #stats_ddl
WITH ( DISTRIBUTION = HASH([seq_nmbr])
, LOCATION = USER_DB
)
AS
WITH T
AS
(
SELECT t.[name] AS [table_name]
, s.[name] AS [table_schema_name]
, c.[name] AS [column_name]
, c.[column_id] AS [column_id]
, t.[object_id] AS [object_id]
, ROW_NUMBER()
OVER(ORDER BY (SELECT NULL)) AS [seq_nmbr]
FROM sys.[tables] t
JOIN sys.[schemas] s ON t.[schema_id] = s.[schema_id]
JOIN sys.[columns] c ON t.[object_id] = c.[object_id]
LEFT JOIN sys.[stats_columns] l ON l.[object_id] = c.[object_id]
AND l.[column_id] = c.[column_id]
AND l.[stats_column_id] = 1
LEFT JOIN sys.[external_tables] e ON e.[object_id] = t.[object_id]
WHERE l.[object_id] IS NULL
AND e.[object_id] IS NULL -- not an external table
)
SELECT [table_schema_name]
, [table_name]
, [column_name]
, [column_id]
, [object_id]
, [seq_nmbr]
, CASE @create_type
WHEN 1
THEN CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+')' AS VARCHAR(8000))
WHEN 2
THEN CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+') WITH FULLSCAN' AS VARCHAR(8000))
WHEN 3
THEN CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+') WITH SAMPLE '+CONVERT(varchar(4),@sample_pct)+' PERCENT' AS VARCHAR(8000))
END AS create_stat_ddl
FROM T
;
DECLARE @i INT = 1
, @t INT = (SELECT COUNT(*) FROM #stats_ddl)
, @s NVARCHAR(4000) = N''
;
WHILE @i <= @t
BEGIN
SET @s=(SELECT create_stat_ddl FROM #stats_ddl WHERE seq_nmbr = @i);
PRINT @s
EXEC sp_executesql @s
SET @i+=1;
END
DROP TABLE #stats_ddl;
Чтобы создать статистику для всех столбцов в таблице с помощью параметров по умолчанию, выполните хранимую процедуру.
EXEC [dbo].[prc_sqldw_create_stats] 1, NULL;
Чтобы создать статистику для всех столбцов в таблице с помощью полного сканирования, просто вызовите эту процедуру.
EXEC [dbo].[prc_sqldw_create_stats] 2, NULL;
Чтобы создать пример статистики для всех столбцов в таблице, введите 3 и процент выборки. Эта процедура использует 20 процентов выборки.
EXEC [dbo].[prc_sqldw_create_stats] 3, 20;
Примеры: обновление статистики
Чтобы обновить статистику, можно:
- Обновить один объект статистики. Указать имя объекта статистики, который вы хотите обновить.
- Обновить все объекты статистики для таблицы. Указать имя таблицы, а не один объект статистики.
Обновление одного указанного объекта статистики
Для обновления указанного объекта статистики используйте следующий синтаксис:
UPDATE STATISTICS [schema_name].[table_name]([stat_name]);
Например:
UPDATE STATISTICS [dbo].[table1] ([stats_col1]);
Обновляя определенные объекты статистики, можно свести к минимуму затраты времени и ресурсов на управление статистикой. Для этого необходимо хорошенько подумать, чтобы выбрать объекты статистики, наиболее подходящие для обновления.
Обновление всей статистики для таблицы
Ниже показан простой метод обновления всех объектов статистики для таблицы.
UPDATE STATISTICS [schema_name].[table_name];
Например:
UPDATE STATISTICS dbo.table1;
Оператор UPDATE STATISTICS
легко использовать. Просто помните, что она обновляет всю статистику для таблицы и, следовательно, может выполнять больше работы, чем необходимо. Если производительность не является проблемой, это самый простой и самый полный способ гарантировать актуальность статистики.
Примечание.
При обновлении всей статистики в таблице выделенный пул SQL проверяет выборку таблицы для каждого объекта статистики. Если таблица большого размера и содержит много столбцов и статистики, может оказаться эффективнее обновлять отдельные данные статистики по необходимости.
Реализация процедуры UPDATE STATISTICS
приведена в разделе о временных таблицах. Метод реализации слегка отличается от процедуры CREATE STATISTICS
, описанной выше, но результат одинаков.
Полный синтаксис приведен в разделе об обновлении статистики.
Метаданные статистики
Существует несколько системных представлений и функций, которые можно использовать для поиска информации о статистике. Например, можно узнать, устарел ли объект статистики, воспользовавшись функцией stats-date, чтобы посмотреть, когда статистика была в последний раз создана или обновлена.
Представления каталога для статистики
Вот какие системные представления показывают информацию о статистике:
Представление каталога | Description |
---|---|
sys.columns | Одна строка для каждого столбца |
sys.objects | Одна строка для каждого объекта в базе данных |
sys.schemas | Одна строка для каждой схемы в базе данных |
sys.stats | Одна строка для каждого объекта статистики |
sys.stats_columns | Одна строка для каждого столбца в объекте статистики; ссылки обратно на sys.columns |
sys.tables | Одна строка для каждой таблицы (включает внешние таблицы) |
sys.table_types | Одна строка для каждого типа данных |
Системные функции для статистики
Эти системные функции полезны для работы со статистикой:
Системная функция | Description |
---|---|
STATS_DATE | Дата последнего обновления объекта статистики |
DBCC SHOW_STATISTICS | Сводный уровень и подробные сведения о распределении значений, которые понимаются объектом статистики |
Сочетание столбцов и функций статистики в одном представлении
Это представление объединяет столбцы, связанные со статистикой и результатами STATS_DATE()
функции.
CREATE VIEW dbo.vstats_columns
AS
SELECT
sm.[name] AS [schema_name]
, tb.[name] AS [table_name]
, st.[name] AS [stats_name]
, st.[filter_definition] AS [stats_filter_definition]
, st.[has_filter] AS [stats_is_filtered]
, STATS_DATE(st.[object_id],st.[stats_id])
AS [stats_last_updated_date]
, co.[name] AS [stats_column_name]
, ty.[name] AS [column_type]
, co.[max_length] AS [column_max_length]
, co.[precision] AS [column_precision]
, co.[scale] AS [column_scale]
, co.[is_nullable] AS [column_is_nullable]
, co.[collation_name] AS [column_collation_name]
, QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
AS two_part_name
, QUOTENAME(DB_NAME())+'.'+QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
AS three_part_name
FROM sys.objects AS ob
JOIN sys.stats AS st ON ob.[object_id] = st.[object_id]
JOIN sys.stats_columns AS sc ON st.[stats_id] = sc.[stats_id]
AND st.[object_id] = sc.[object_id]
JOIN sys.columns AS co ON sc.[column_id] = co.[column_id]
AND sc.[object_id] = co.[object_id]
JOIN sys.types AS ty ON co.[user_type_id] = ty.[user_type_id]
JOIN sys.tables AS tb ON co.[object_id] = tb.[object_id]
JOIN sys.schemas AS sm ON tb.[schema_id] = sm.[schema_id]
WHERE 1=1
AND st.[user_created] = 1
;
Примеры DBCC SHOW_STATISTICS()
DBCC SHOW_STATISTICS()
показывает данные, удерживаемые в объекте статистики. Эти данные состоят из трех частей:
- Верхний колонтитул
- Вектор плотности
- Гистограмма
Заголовок метаданных о статистике. Гистограмма отображает распределение значений в первом ключевом столбце объекта статистики. Вектор плотности измеряет корреляцию между столбцами.
Примечание.
Выделенный пул SQL вычисляет оценку кратности с помощью данных в объекте статистики.
Отображение заголовка, плотности и гистограммы
Этот простой пример показывает все три части объекта статистики.
DBCC SHOW_STATISTICS([<schema_name>.<table_name>],<stats_name>)
Например:
DBCC SHOW_STATISTICS (dbo.table1, stats_col1);
Отображение одной или нескольких частей DBCC SHOW_STATISTICS()
Если вы заинтересованы только в просмотре определенных частей, используйте предложение WITH
и укажите, какие части требуется показать:
DBCC SHOW_STATISTICS([<schema_name>.<table_name>],<stats_name>) WITH stat_header, histogram, density_vector
Например:
DBCC SHOW_STATISTICS (dbo.table1, stats_col1) WITH histogram, density_vector
Отличия DBCC SHOW_STATISTICS()
DBCC SHOW_STATISTICS()
реализуется в выделенном пуле SQL строже, чем в SQL Server:
- Недокументированные возможности не поддерживаются.
- Не удается использовать
Stats_stream
. - Невозможно соединить результаты для определенных подмножеств данных статистики. Например,
STAT_HEADER JOIN DENSITY_VECTOR
. -
NO_INFOMSGS
невозможно задать для подавления сообщений. - Невозможно использовать квадратные скобки вокруг имен статистики.
- Невозможно использовать имена столбцов для идентификации объектов статистики.
- Пользовательская ошибка 2767 не поддерживается.