Восходящая ключевая проблема - ведущий столбец с маркой «стационарный» - SQL Server

9

Я исследовал медленные запросы в нашей базе данных и пришел к выводу, что это классическая проблема возрастающих ключей. Поскольку новые строки вставляются практически постоянно, а определенный фрагмент SQL для извлечения последних данных из БД запускается каждые 30 минут, первый вариант обновления статистики каждые 30 минут звучит так, будто это может быть пустой тратой ресурсов.

Итак, я посмотрел на Trace Flag 2389, который в принципе должен помочь, однако для этого требуется, чтобы столбец Leading был маркирован как Ascending, и когда я использовал Trace Flag 2388 для проверки статистики индекса (PK), я вижу, что ведущий столбец на самом деле помечается как стационарный - как это происходит для нескольких индексов PK в других таблицах, обновляемых одновременно.

введите описание изображения здесь

Похоже, нет особых указаний на то, что приводит к брендингу Stationary, однако я обнаружил, что KB2952101 говорит, что если бы менее 90% вкладок было больше, чем старое максимальное значение, оно было бы классифицировано как стационарное. Все наши вставки являются новыми отправками, а ведущий столбец - это столбец bigint IDENTITY, поэтому 100% вставок должно быть больше максимального предыдущего значения.

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

Более ранняя попытка решить эту проблему для некоторого ежедневного запуска SQL (который работал очень хорошо) привела к настройке задания для ночного обновления статистики для этой таблицы. Обновление не выполняет FULLSCAN, поэтому может ли быть так, что при выборочном сканировании иногда пропускаются новые строки, поэтому оно не всегда отображается в порядке возрастания?

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

Сервер является SQL Server 2012 SP1.

Обновление : еще один день, еще одно обновление статистики - тот же стационарный брендинг. Со времени предыдущего обновления статистики было добавлено 28049 новых вкладок. Каждая строка имеет метку времени, когда она была вставлена, поэтому, если я выбираю max (id) из таблицы, где метка времени <'20161102', я получаю 23313455 Аналогично, если я делаю это для того времени, когда статистика обновлялась сегодня, я получаю 23341504.

Разница между ними заключается в 28049 новых вставках, так что, как вы можете видеть, все новые вставки получили новые восходящие ключи (как и ожидалось), предполагая, что передний столбец должен маркироваться как восходящий, а не как стационарный.

За тот же период наша работа по архивированию удалила 213 629 строк (мы медленно очищаем старые данные). Есть ли вероятность того, что сокращение количества строк может способствовать стационарному брендингу? Я проверял это раньше, и, похоже, это не имело никакого значения.

Обновление 2 : еще один день, еще одно обновление статистики, и столбец теперь помечен как «По возрастанию»! Согласно теории удаления, влияющей на это, я проверил процент обновлений, являющихся вставками, по сравнению с удалениями, и вчера 13% были вставками, тогда как предыдущие два дня вставки составляли около 12%. Я не думаю, что это дает нам что-либо убедительное.

Интересно, что связанная таблица, которая получает в среднем 4 строки, вставленные для каждой строки, вставленной в эту основную таблицу, и обновляет свою статистику в то же время, имеет свой столбец IDENTITY PK все еще как стационарная !?

Обновление 3 : в выходные мы получаем больше вкладышей. Этим утром ведущая колонна вернулась в Стационар. В последнем обновлении статистики у нас было 46840 вставок и только 34776 удалений.

Опять же, что интересно, у упомянутой выше таблицы, по которой я упоминал, теперь есть ведущая колонка, помеченная как Ascending. Нет документации, которая могла бы объяснить это?

Обновление 4 : Прошла неделя или около того, задание архивирования очистило отставание, поэтому мы последовательно удаляем около двух третей от числа вставляемых строк. Статистика показывает смешанные результаты в связанных таблицах, одна показывает стационарную, а две - восходящую, несмотря на то, что все они обновляются пропорционально аналогичным образом.

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

Ответы:

3

Похоже, нет особых указаний относительно того, что приводит к брендингу Stationary, однако я обнаружил, что KB2952101 говорит, что если менее чем на 90% вкладок больше старого максимального значения, оно будет классифицировано как стационарное. Все наши вставки являются новыми отправками, а ведущий столбец - это столбец bigint IDENTITY, поэтому 100% вставок должно быть больше максимального предыдущего значения.

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

Это будет фирменный стационар, если, как вы уже заявили, 10% или более вкладышей не возрастают. Если бы 100% ваших вставок были такими, как вы говорите ... тогда у вас может не быть этой проблемы, пока, конечно, вы не удалите, но тогда она вернется к неизвестному.

Вот репродукция вашей проблемы:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go
Шон Галларди - Пользователь на пенсии
источник
Я провел быстрый тест, используя тот же скрипт, что и выше, но только запустил вставку и удаление частей. Кажется, если вы удалите значительно большее количество строк, чем вставлено, он вернется обратно к стационарному (снова около 10%). В ваши обновленные данные вы вставили примерно 10% всех сделанных изменений данных - кажется, что удаление доставляет вам горе. На этом этапе я бы предложил разрешить объекту статистики попадать по возрастанию, а затем заморозить его, не обновляя его.
Шон Галларди - Пенсионер
Я попытался воссоздать то, что вы сделали, и закончил тем, что добавил еще 10 строк и удалил 1000, обновил статистику, затем показал статистику, и он по-прежнему отображается в порядке возрастания: вставок с момента последнего обновления: 10, удалений с момента последнего обновления: 1000, тип ведущего столбца : Восходящий. Не уверен, почему я получаю другой результат для вас? Если ваши выводы верны, то это может быть просто случай, когда вам приходится мириться с неоптимальными результатами, а затем, когда наше отставание в архивировании очистится, попробуйте снова.
Ник
0

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

Кроме того, вы пробовали Trace Flag 2371.

TF 2371 документирован здесь .

КБ называется «Управление поведением Autostat (AUTO_UPDATE_STATISTICS) в SQL Server». и KB составляет 2754171.

Было бы очень полезно, если бы вы перечислили для нас фактическое влияние новых данных, не вовремя попадающих в статистику.

Были выбраны неверные индексы. И, если да, можете ли вы перечислить нам индексы и их первичные ключи?

Кроме того, можете ли вы поделиться планами, которые генерируются, когда статистика датируется, когда они являются своевременными. Я хотел бы сравнить два.

Я думаю, что решения SQL Cost Based Optimizer (правила и калькуляция) довольно хороши; за пределами эзотерических областей, как этот.

Если это особый случай, может быть полезным более подробное объяснение и оправдание открытия элемента Connect.

Кроме того, по моему скромному мнению, у вас будет больше общих преимуществ в том, что поставщик будет использовать SP, чем специальный SQL.

Даниэль Адениджи
источник
Спасибо, все идентификаторы созданы SQL Server. Я понимаю, что флаг 2371 только делает обновления статистики более частыми. Судя по таблице на brentozar.com/archive/2016/03/… , нашему размеру таблицы (14M строк) и количеству ежедневных вставок (28K строк), статистика будет обновляться только каждые 4 дня или около того, поэтому При извлечении новых данных большую часть времени не будут знать о новых данных. Запросы, на которые я смотрел, не являются проблемой, это понимание того, как SQL Server маркирует ведущую колонку, которую я хотел бы знать. Еще раз спасибо.
Ник