Улучшение производительности запросов для секционированных представлений с большим количеством таблиц

Фон

Я перенесу приложение из схемы с одной таблицей событий, содержащей 0,5-1,3 миллиарда записей, в секционированные представления с 30-180 идентичными базовыми таблицами, каждая из которых содержит часть этого количества записей, что значительно облегчает ряд проблем, возникающих вокруг управление и запрос такого количества записей. Я использую секционированные представления вместо секционирования таблиц, потому что не все мои пользователи имеют доступ к Awesome Edition SQL Server 2012.

Функция разделения основана на декартовом произведении дня события и одном атрибуте события. Другими словами, все события за 2015 год с 01 июня с атрибутом "foo" были помещены в таблицу типа "Event20150601_foo", все события с атрибутом "bar" перешли в "Event20150601_bar", и на следующий день события перейдут в "Event20150602_foo" и "Event20150602_bar" и т. Д. Обычно есть 2-3 значения атрибута и 15-60 дней событий, которые соответствуют типичному диапазону 30-180 различных таблиц.

Базовая структура каждой таблицы представляет собой составной кластерный первичный ключ, состоящий из EventId (bigint) и PartitionKey (int), за которым следует несколько других неиндексированных столбцов. EventId уникален, монотонно увеличивается во всех таблицах и реализуется с помощью последовательности. PartitionKey уникален для каждой секционированной таблицы, поэтому проверочное ограничение для каждой таблицы просто "CHECK (PartitionKey = x)", где x определяется для каждой таблицы секций. Это позволяет мне выполнять поиск по EventId через поиск по кластерному индексу, даже если я не могу предоставить ключ раздела, чтобы сузить область поиска. В случае, когда я могу предоставить и EventId, и PartitionKey, запрос очень эффективен, поскольку оптимизатор может затем выполнять поиск по индексу только для одной таблицы, которая соответствует ключу раздела, что является большим выигрышем в производительности.

эксперимент

Это сделало бы мою жизнь еще проще, если бы я мог пойти еще более детально и разбить на части в зависимости от дня события и более широкой комбинации атрибутов (500-5000 вместо вышеупомянутых 2-3), которые затем потребовали бы от меня в ассортимент 10 000-50 000 разных перегородок. Я проверил это на базе данных с 20 000 различных таблиц и, к сожалению, обнаружил, что время выполнения различных операций увеличивается с линейной скоростью по сравнению с количеством таблиц. Согласно статистике запросов, большая часть времени была потрачена на анализ и компиляцию запроса, а не на его выполнение.

Вот время выполнения, которое я нашел для различных операций (простите за элементарную таблицу):

  • Создать разделенное представление
    • 100 tables : 50ms
    • 1000 tables : 800ms
    • 2000 tables : 2,660ms
    • 4000 tables : 10,000ms
    • 16000 tables: 225,000ms
  • select * from PartitionedView where EventId = x (сканирует все таблицы)
    • 100 tables : 78ms parse/compile time; 25ms exec time
    • 1000 tables : 3,500ms parse/compile time; 160ms exec time
    • 2000 tables : 15,000ms parse/compile time; 500ms exec time
    • 4000 tables : 68,000ms parse/compile time; 2,000ms exec time
    • 16000 tables: Отменено после> 10 минут анализа / компиляции!
  • select * from PartitionedView where (EventId = x) and (PartitionKey = y) (сканирует только одну таблицу)
    • 100 tables : 74ms parse/compile time; 1ms exec time
    • 1000 tables : 2,500ms parse/compile time; 15ms exec time
    • 2000 tables : 11,000ms parse/compile time; 10ms exec time
    • 4000 tables : 50,000ms parse/compile time; 16ms exec time
    • 16000 tables: Отменено после> 10 минут анализа / компиляции!

Вопрос

Должен ли я быть отчитан за то, что даже подумал об использовании такого количества таблиц? Если нет, то есть ли способ уменьшить время анализа и компиляции запросов при наличии большого количества таблиц?

0 ответов

Другие вопросы по тегам