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


8

Я сталкиваюсь со странной проблемой, возникающей при доступе к историческим записям во временной таблице. Запросы, которые обращаются к более старым записям во временной таблице через подпункт AS OF, занимают больше времени, чем запросы к последним историческим записям.

Хронологическая таблица была сгенерирована SQL Server (включает кластерный индекс для столбцов даты и использует сжатие страниц), я добавил 50 млн строк в хронологическую таблицу, и мои запросы получили около 25 000 строк.

Я попытался определить причину проблемы, но не смог ее идентифицировать. Пока что я проверил:

  • Создание тестовой таблицы с 50 миллионами строк с кластеризованным индексом, чтобы увидеть, было ли замедление вызвано просто объемом. Мне удалось получить 25K строк в постоянное время (~ 400 мс).
  • Удаление сжатия страницы из исторической таблицы. Это не повлияло на время поиска, но значительно увеличило размер таблицы.
  • Я попытался получить доступ к строкам таблицы истории напрямую, используя столбец идентификатора и столбцы даты. Здесь все было немного интереснее. Я мог получить доступ к более старым строкам в таблице на ~ 400 мс, где, как и в случае с подпунктом AS OF, это заняло бы ~ 1200 мс. Я попытался выполнить фильтрацию в своей тестовой таблице в столбце даты и заметил аналогичное замедление по сравнению с фильтрацией в столбце идентификатора. Это приводит меня к мысли, что сравнение дат стоит за некоторым замедлением.

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

Планы выполнения

Это простые поисковые запросы: первый обращается к более старым строкам, второй обращается к новым строкам.

Старые ряды ~ 1200мс время выполнения

Последние строки ~ 350мс время выполнения

Детали таблицы

Это столбцы во временной таблице. Таблица истории имеет те же столбцы, но не имеет первичного ключа (согласно требованиям таблицы истории): Столбец темпоральной таблицы

Ниже приведены индексы в таблице истории: Индексы в таблице истории

Ответы:


6

В комментарии Зейна на ваш вопрос он заявил:

... Похоже, частью вашей проблемы является то, что вы читаете 50 миллионов строк, чтобы вернуть 20К в плане.

Это действительно проблема. Нет доступного индекса для передачи некоторых или всех предикатов в механизм хранения. Microsoft рекомендует эту базовую стратегию индексирования для временных таблиц в статье Документов. Особенности и ограничения временных таблиц :

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

Формулировка этого немного сбивает с толку (во всяком случае, для меня). Но выгода состоит в том, что вы могли бы создать эти индексы для повышения производительности, если не очень много:

Индекс NC для текущей таблицы, начинающийся с SysEndTime:

CREATE NONCLUSTERED INDEX IX_SysEndTime_SysStartTime 
ON dbo.Benefits (SysEndTime, SysStartTime)
/*INCLUDE (ideally, include your other important fields here)*/;

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

ТПП в таблице истории

CREATE CLUSTERED COLUMNSTORE INDEX ix_BenefitsHistory
ON dbo.BenefitsHistory
WITH (DROP_EXISTING = ON);

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

Индекс NC для текущей таблицы, начинающийся с SysStartTime:

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

CREATE NONCLUSTERED INDEX IX_SysStartTime_SysEndTime
ON dbo.Benefits (SysStartTime, SysEndTime)
/*INCLUDE (ideally, include your other important fields here)*/;

Создание 3 описанных выше индексов существенно изменило использование ресурсов в моих тестовых примерах. Я создал тестовый пример, который запускает два запроса, которые возвращают 1,5 миллиона строк. И история, и текущие таблицы имеют 50 миллионов строк).

Примечание. Чтобы снизить издержки SSMS, я запустил тест с включенной опцией «Отменить результаты после выполнения».

План выполнения - индексы по умолчанию

Логические чтения: 1330612
Процессорное время: 00: 00: 14.718
Истекшее время: 00: 00: 06.198

План выполнения - с указанными выше индексами

Логические чтения: 27 656 (хранилище строк 8111 + хранилище столбцов 19 545).
Время процессора: 00: 00: 01.828
Истекшее время: 00: 00: 01.150

Как вы можете видеть, все 3 такта значительно упали - включая общее прошедшее время, от 6 секунд до 1 секунды.


Другой вариант, представленный в статье «Документы», - отказаться от двух индексов NC в текущей таблице в пользу кластеризованного индекса columnstore. В моем тесте производительность была очень похожа на решение для индексирования, описанное выше.


2

Предложение FOR SYSTEM TIME AS OFпытается вернуть набор данных, поскольку он существовал в указанное время. Это означает, что обновления должны откатываться внутренне, удаления должны быть «восстановлены», а вставки должны игнорироваться в зависимости от системного времени запроса.

Чем дальше в прошлом время AS OF, тем больше работы нужно проверить, чтобы убедиться, что временная таблица существует так, как она существовала в указанное системное время, и, следовательно, дольше будет выполняться запрос.

Если таблица данных является просто таблицей регистрации, и в данные не вносятся никакие изменения, тогда используется зарегистрированная дата, и индекс будет возвращать данные быстрее и более согласованно. Использовать ли временные функции в этом случае нет необходимости. Однако если в строки вносятся изменения (кроме вставок), то использование функции временной таблицы - единственный способ вернуть точные запрашиваемые данные (состояние таблицы в том виде, в котором она существовала в это конкретное время), и вы будете просто нужно принять дополнительные накладные расходы временных запросов.

Примечание. «Откаты» не являются фактическими откатами. Временные таблицы используют две таблицы - текущую таблицу и таблицу истории. Когда строка изменяется, копия предыдущей версии вставляется в таблицу истории с интервалом времени, в течение которого строка была действительной. Если вы вставите строку в 20.10.2008 10: 20: 20.18, обновите значение в 25.10.2008 10: 25: 20.18 и обновите его снова в 12/01/2018 12: 01: 20.18, у вас есть последняя версия строки в таблице Current с датой начала от 12/12/2018 12: 01: 20.18 и две строки в таблице истории с допустимыми диапазонами от 10/20 до 25/25/2018, а также 10 / С 25 по 12/01/2018


Спасибо за ответ! Это определенно имеет интуитивный смысл, но я не нашел никакого упоминания об этом типе поведения в документах, которые я читал (я только прошел основы временной таблицы в документах MS). Знаете ли вы какую-либо документацию, которая описывает поведение более подробно?
Эбрахим Бехбахани
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.