Как оптимизировать выравнивание хранилища столбцов SQL Server

У меня есть таблица Clustered Columnstore Index Table для наших показателей IOT (данные временных рядов). Он содержит более 1 миллиарда строк и имеет следующую структуру:

CREATE TABLE [dbo].[Data](
[DeviceId] [bigint] NOT NULL,
[MetricId] [smallint] NOT NULL,
[TimeStamp] [datetime2](2) NOT NULL,
[Value] [real] NOT NULL
)

CREATE CLUSTERED INDEX [PK_Data] ON [dbo].[Data] ([TimeStamp],[DeviceId],[MetricId]) --WITH (DROP_EXISTING = ON)
CREATE CLUSTERED COLUMNSTORE INDEX [PK_Data] ON [dbo].[Data] WITH (DROP_EXISTING = ON, MAXDOP = 1, DATA_COMPRESSION = COLUMNSTORE_ARCHIVE)

Существует около 10 000 различных значений DeviceId и диапазон временных меток с 2008 года по настоящее время. Типичный запрос к этой таблице выглядит так:

SET STATISTICS TIME, IO ON
SELECT
    [DeviceId]
    ,[MetricId]
    ,DATEADD(hh, DATEDIFF(day, '2005-01-01', [TimeStamp]), '2005-01-01') As [Date]
    ,MIN([Value]) as [Min]
    ,MAX([Value]) as [Max]
    ,AVG([Value]) as [Avg]
    ,SUM([Value]) as [Sum]
    ,COUNT([Value]) as [Count]
FROM
    [dbo].[Data]
WHERE
    [DeviceId] = 6077129891325167032
    AND [MetricId] = 1000
    AND [TimeStamp] BETWEEN '2017-07-01' AND '2017-07-30'
GROUP BY
    [DeviceId]
    ,[MetricId]
    ,DATEDIFF(day, '2005-01-01', [TimeStamp])
ORDER BY
    [DeviceId]
    ,[MetricId]
    ,DATEDIFF(day, '2005-01-01', [TimeStamp])

Когда я выполняю этот запрос, я получаю это для показателей производительности:

Поскольку на данный момент запрос, подобный указанному выше, выполняет слишком много чтений сегментов, я считаю:

Table 'Data'. Scan count 2, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 5257, lob physical reads 9, lob read-ahead reads 4000.
Table 'Data'. Segment reads 11, segment skipped 764.

План запроса: План запроса

Я считаю, что это плохо оптимизировано, поскольку было прочитано 11 сегментов, чтобы получить только 212 из 1 миллиарда исходных строк (до группировки/агрегации).

Затем я запустил отличные сценарии Нико Нойгебауэра, чтобы проверить нашу настройку и выравнивание Columnstore https://github.com/NikoNeugebauer/CISL/blob/master/Azure/alignment.sql, я получаю этот результат после перестроения кластеризованного индекса Columnstore:

Выравнивание хранилища столбцов

Столбцы MetricId и TimeStamp имеют оптимальную оценку выравнивания 100%. Как мы можем убедиться, что столбец DeviceId также правильно выровнен? Я играл с порядком столбцов в исходном индексе Clustered (Rowstore), можно ли что-то оптимизировать?


person Ted van der Veen    schedule 05.08.2017    source источник
comment
пожалуйста, вставьте план запроса в формате xml   -  person TheGameiswar    schedule 05.08.2017
comment
если вы используете sql server 2016, попробуйте использовать dbcc clonedb и поделиться базой данных, чтобы другие могли воспроизвести точный сценарий, с которым вы столкнулись. если вы не используете 2016, вы можете написать нашу схему таблицы, индексы, статистику и попробовать поделиться сценарий   -  person TheGameiswar    schedule 05.08.2017
comment
@TheGameiswar DBCC CLONEDATABASE доступна начиная с SQL Server 2014 SP2 :)   -  person wBob    schedule 05.08.2017
comment
@wBob: отлично, спасибо за информацию   -  person TheGameiswar    schedule 05.08.2017
comment
@TheGameiswar, пожалуйста, найдите XML-план запроса здесь: pastebin.com/y0fVDqe2   -  person Ted van der Veen    schedule 05.08.2017
comment
как насчет создания отсутствующего индекса.?   -  person TheGameiswar    schedule 06.08.2017
comment
@TheGameiswar добавление отсутствующего индекса, предложенного планом запроса, как бы противоречит всей цели кластеризованного индекса columnstore, который мы стремимся использовать также для экономии места для хранения. Я сделал быстрый тест и создал индекс в тестовой таблице с той же структурой (но с 3% строк). Как видите, экономия пространства испарилась (50 МБ для данных columnstore против 1,2 ГБ для добавленного индекса) imagebin.ca/v/3VwKKEezWGFa   -  person Ted van der Veen    schedule 06.08.2017
comment
я не совсем уверен насчет внутренних индексов хранилища столбцов, но в целом, если у вас есть индекс, который не удовлетворяет запросу, вам придется пойти на компромисс. Мне нужно, чтобы этот запрос был быстрее или это как это один из запросов, так что меня устраивает его текущая скорость   -  person TheGameiswar    schedule 06.08.2017
comment
Кроме того, наличие кластеризованного индекса не означает, что он должен удовлетворять все запросы.   -  person TheGameiswar    schedule 06.08.2017
comment
Вы вообще делали какое-либо обслуживание индекса? В моих локальных испытаниях я загрузил таблицу более чем 16 миллионами строк случайных данных, и мое выравнивание исправно. Кроме того, индекс не помешал бы цели. В индексе есть включение, чтобы добавить столбец Value для ускорения запроса. Возможно, вы захотите переключить свой индекс COLUMNSTORE на некластеризованный и включить столбец Value.   -  person tj-cappelletti    schedule 06.08.2017
comment
@virusstorm Вы сравнивали требования к хранилищу между кластеризованной версией Columnstore вашей тестовой таблицы и некластеризованной? Последнее потребует как минимум на 2000% больше места на диске. Это то, чего мы хотим избежать, поскольку таблица в конечном итоге будет содержать около 10 миллиардов записей.   -  person Ted van der Veen    schedule 07.08.2017
comment
Просто измените кластеризованный индекс на (DeviceId, MetricId, TimeStamp). Это должно решить это.   -  person Evaldas Buinauskas    schedule 07.08.2017


Ответы (2)


ключевое решение для выравнивания вашей таблицы по DeviceId состоит в том, чтобы построить кластеризованный индекс rowstore для вашей таблицы, а затем построить по нему кластеризованный индекс Columnstore с MAXDOP = 1 (чтобы не создавать каких-либо перекрытий, которые имеют место, когда построение индекса выполняется с несколькими ядрами). ). Таким образом, возможный код будет выглядеть примерно так:

CREATE CLUSTERED INDEX [PK_Data] ON [dbo].[Data] ([DeviceId],[TimeStamp],[MetricId]) --WITH (DROP_EXISTING = ON)
CREATE CLUSTERED COLUMNSTORE INDEX [PK_Data] ON [dbo].[Data] WITH (DROP_EXISTING = ON, MAXDOP = 1, DATA_COMPRESSION = COLUMNSTORE_ARCHIVE)

Другой возможностью было бы сделать все это внутри CISL, подготовив и затем выполнив функцию выравнивания:

insert into dbo.cstore_Clustering( TableName, Partition, ColumnName )
    VALUES ('[dbo].[Data]', 1, 'DeviceId' );

Хотя это только для 1 раздела, но вам все равно следует подумать о разбиении таблицы, как только вы получите числа, которые вы используете. После настройки вы можете начать выполнять dbo.cstore_doAlignment, который автоматически выровняет и оптимизирует вашу таблицу. (У вас будут некоторые параметры для настройки порога оптимизации, если хотите)

С уважением, Нико

person Niko Neugebuer    schedule 07.08.2017
comment
Спасибо @Нико. Итак, правильно ли я понимаю ваш ответ, для нашего случая использования, когда у нас есть таблица только добавления/регистрации для наших показателей IOT, мы должны разделить таблицу по столбцу TimeStamp (в месяц?), а затем выровнять эту таблицу по DeviceId? В нашей агрегации мы всегда запрашиваем один DeviceId, возможно несколько разных MetricId и TimeStamp в диапазоне от 1 до 12 месяцев (группировка по часам и дням соответственно). - person Ted van der Veen; 07.08.2017
comment
Тед, не вдаваясь в подробности (которые могут изменить мое восприятие), я согласен, что разделение по TimeStamp и выравнивание по DeviceId выглядит как прекрасный вариант. С уважением, Нико - person Niko Neugebuer; 10.08.2017
comment
Еще раз большое спасибо, @Niko! Я реализовал разбиение по месяцам на TimeStamp плюс выравнивание по DeviceId. Результаты многообещающие, но требуют дополнительной проверки, поскольку большинство (75%) запросов выполняются за 100 мс, а 25% — за 2000 мс. Не так много между ними. Все это работает в эластичном пуле Azure SQL Premium. Итак, это тот же запрос, который выполняется один раз каждые 3 секунды, поэтому предел дроссельной заслонки отсутствует. Каковы будут ваши предложения по объему строк разделов секционирования? Сейчас я выбираю месяц, но, может быть, это приводит к слишком большому количеству разделов? - person Ted van der Veen; 11.08.2017
comment
Спасибо @NikoNeugebuer за то, что вы есть! :) Ваш блог потрясающий! У меня есть сценарий, аналогичный упомянутому выше, и когда я пытаюсь применить выравнивание сегментов к DeviceID, а моя таблица разбита на месяц по TimeStamp, столбец все еще смещен. Он выравнивает его по TimeStamp. DeviceID выровнен на 0%. (в Azure SQL) Создайте индекс для (DeviceID) в MonthlyPartScheme (TimeStamp). Как применить выравнивание сегментов в разделах? - person datamodel; 28.03.2019

Когда Max dop установлен равным 1 для создания хранилища кластеризованных столбцов, ваши записи будут эффективно сортироваться, но для таблицы с 1 миллиардом строк этот max dop 1 вам не поможет. Лучше разбить таблицу на разделы с любым столбцом даты, а затем создать индекс хранилища кластеризованных столбцов с максимальным значением dop, превышающим 1 или 0. Но в этом случае сортировка не будет гарантирована, но индекс хранилища кластеризованных столбцов будет выполнять сегмент устранение эффективно. Следует четко отметить, что не удаляйте и не создавайте кластерный индекс хранилища столбцов, сохраняя любой другой некластеризованный индекс в своей таблице, это повлияет на производительность создания/удаления кластеризованного индекса хранилища столбцов. Если вы удалите кластеризованный индекс хранилища столбцов, сохранив другой индекс, SQL-сервер выполнит много работы с другими индексами.

person Kannan.C    schedule 31.07.2019