Не уверен, что это ошибка, сама по себе, но это определенно интересное явление. Оперативные перестройки разделов являются новыми в SQL Server 2014, поэтому с этим можно разобраться.
Вот мое лучшее объяснение для вас. Инкрементная статистика абсолютно требует, чтобы все разделы отбирались с одинаковой частотой, чтобы при объединении движка страниц статистики можно было с уверенностью сопоставить выборочное распределение. REBUILD
обязательно выборки данных с частотой выборки 100%. Нет никакой гарантии, что частота выборки 100% в разделе 9 всегда будет точной частотой дискретизации остальных разделов. Из-за этого создается впечатление, что движок не может объединить сэмплы, и в результате вы получаете пустой блок статистики. Тем не менее, объект статистики все еще там:
select
check_time = sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
stats_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
outer apply sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
where t.name = 'TransactionHistory' and sh.name = 'dbo'
Вы можете заполнить блоб любым количеством способов:
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;
или
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);
или вы можете дождаться обновления AutoStats при первой компиляции плана запроса с использованием этого объекта:
-- look at my creative query
select *
from dbo.TransactionHistory
where TransactionDate = '20140101';
Сказав все это, этот просветляющий пост Эрин Стеллато подчеркивает то, что стало восприниматься как серьезный недостаток дополнительных статистических данных. Их данные уровня раздела не используются оптимизатором при генерации плана запроса, что снижает предполагаемое преимущество добавочной статистики. Какова же тогда текущая выгода от добавочной статистики? Я бы сказал, что их основная полезность заключается в возможности более последовательно выбирать большие таблицы с большей скоростью, чем при традиционной статистике.
Используя ваш пример, вот как все выглядит:
set statistics time on;
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 94 ms, elapsed time = 131 ms.
update statistics dbo.TransactionHistory(IDX_ProductId)
with resample on partitions(2);
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 5 ms.
drop index IDX_ProductId On dbo.TransactionHistory;
CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId)
WITH (DATA_COMPRESSION = ROW)
ON [PRIMARY]
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 76 ms, elapsed time = 66 ms.
Обновление статистики полного сканирования дополнительной статистики стоит 131 мс. Обновление статистики полной развертки для статистики без выравнивания по разделам стоит 66 мс. Несогласованная статистика, скорее всего, медленнее из-за накладных расходов, связанных с объединением отдельных страниц статистики обратно в основную гистограмму., Однако, используя выровненный по разделам статистический объект, мы можем обновить один раздел и объединить его обратно в основной блок гистограммы за 5 мс. Поэтому в этот момент администратор с добавочной статистикой сталкивается с решением. Они могут уменьшить общее время обслуживания своей статистики, обновляя традиционно только разделы, или они могут экспериментировать с более высокими частотами выборки, так что они могут получить больше строк, выбранных за тот же период времени, что и их предыдущий период обслуживания. Первый позволяет получить передышку в окне обслуживания, а второй может перенести статистику по очень большой таблице в место, где запросы получают более точные планы на основе более точной статистики. Это не гарантия, и ваш пробег может отличаться.
Читатель может видеть, что 66 мс - это не болезненное время обновления статистики для этой таблицы, поэтому я попытался настроить тест для набора данных stackexchange. В недавнем дампе, который я скачал, содержится 6 418 608 сообщений (исключая сообщения StackOverflow и все сообщения с 2012 года - ошибка данных с моей стороны).
Я разделил данные, [CreationDate]
потому что ... демо.
Вот некоторые моменты времени для некоторых довольно стандартных сценариев (100% - перестроение индекса, по умолчанию - автоматическое обновление статистики или UPDATE STATISTICS
без указанной частоты выборки:
- Создать неинкрементную статистику с полным сканированием: время ЦП = 23500 мс, прошедшее время = 22521 мс.
- Создание инкрементной статистики с полным сканированием: время ЦП = 20406 мс, прошедшее время = 15413 мс.
- Обновить неинкрементную статистику с частотой дискретизации по умолчанию: время ЦП = 406 мс, прошедшее время = 408 мс.
- Обновление инкрементной статистики с частотой дискретизации по умолчанию: время ЦП = 453 мс, прошедшее время = 507 мс.
Допустим, мы более изощренны, чем эти сценарии по умолчанию, и решили, что частота выборки 10% - это минимальная частота, которая должна дать нам планы, которые нам нужны, при сохранении времени обслуживания на разумные сроки.
- Обновить неинкрементную статистику с выборкой 10 процентов: время ЦП = 2344 мс, прошедшее время = 2441 мс.
- Обновление инкрементной статистики с выборкой 10 процентов: время ЦП = 2344 мс, прошедшее время = 2388 мс.
Пока что нет никакой явной пользы в том, чтобы иметь возрастающую статистику. Однако, если мы используем недокументированную sys.dm_db_stats_properties_internal()
DMV (ниже), вы можете получить представление о том, какие разделы вы хотите обновить. Допустим, мы внесли изменения в данные в разделе 3 и хотим, чтобы статистика была свежей для входящих запросов. Вот наши варианты:
- Обновление неинкрементное по умолчанию (также поведение по умолчанию при автоматическом обновлении статистики): 408 мс.
- Обновление без инкремента при 10%: 2441 мс.
- Обновите инкрементную статистику, раздел 3 с повторной выборкой (10% - наша определенная частота выборки): время ЦП = 63 мс, истекшее время = 63 мс.
Вот где нам нужно принять решение. Берём ли мы победу в 63 мс. обновление статистики на основе разделов, или мы увеличим частоту дискретизации еще выше? Допустим, мы готовы принять начальный показатель выборки на уровне 50% для инкрементальной статистики:
- Обновление инкрементной статистики на 50%: истекшее время = 16840 мс.
- Обновление инкрементной статистики, раздел 3 с повторной выборкой (50% - наше новое время обновления): истекшее время = 295 мс.
Мы можем выбирать намного больше данных, возможно, настроив оптимизатор, чтобы лучше угадывать наши данные (хотя он пока не использует статистику на уровне разделов), и мы можем сделать это быстрее, теперь, когда у нас есть инкрементная статистика.
Впрочем, еще одна забавная вещь. А как насчет синхронных обновлений статистики? Сохраняется ли частота выборки 50% даже при включении автостата?
Я удалил данные из раздела 3, запустил запрос на CreationDate и проверил, а затем проверил ставки с помощью того же запроса, приведенного ниже. Частота дискретизации 50% была сохранена.
Итак, короче говоря: инкрементная статистика может быть полезным инструментом с достаточным количеством мыслей и начальной настройкой. Тем не менее, вы должны знать проблему, которую вы пытаетесь решить, а затем вам нужно решить ее соответствующим образом. Если вы получаете плохие оценки мощности, вы можете получить лучшие планы со стратегической частотой выборки и некоторым вложенным вмешательством. Однако вы получаете только небольшую часть выгоды, поскольку используемая гистограмма представляет собой единую объединенную страницу статистики, а не информацию об уровне раздела. Если вы чувствуете боль в окне технического обслуживания, то, возможно, вам может помочь инкрементная статистика, но, вероятно, вам потребуется настроить процесс вмешательства при техническом обслуживании. Несмотря на,:
- Статистика создается с индексами, которые не выровнены по разделам с базовой таблицей.
- Статистика создается на всегда читаемых вторичных базах данных.
- Статистика создается на базе данных только для чтения.
- Статистика создается по отфильтрованным индексам.
- Статистика создается по просмотрам.
- Статистика создается по внутренним таблицам.
- Статистика создается с использованием пространственных индексов или индексов XML.
Надеюсь это поможет
select
sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
parition_number = isnull(sp.partition_number,1),
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter = coalesce(sp.modification_counter, n1.modification_counter)
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
and (
(is_incremental = 0)
or
(is_incremental = 1 and sp.partition_number is not null)
)
and t.name = 'Posts'
and s.name like 'st_posts%'
order by s.stats_id,isnull(sp.partition_number,1)