Запросы и обновления очень медленно после IndexOptimize

12

База данных SQL Server 2017 Enterprise CU16 14.0.3076.1

Недавно мы попытались переключиться с заданий по техническому обслуживанию на восстановление индекса по умолчанию на Ola Hallengren IndexOptimize. Задания по перестройке индекса по умолчанию выполнялись в течение нескольких месяцев без каких-либо проблем, а запросы и обновления работали с приемлемым временем выполнения. После запуска IndexOptimizeв базе данных:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

производительность была крайне ухудшена. Оператор обновления, который раньше занимал 100 мс, потом IndexOptimizeзанимал 78 000 мс (с использованием идентичного плана), и запросы также выполнялись на несколько порядков хуже.

Поскольку это все еще тестовая база данных (мы переносим производственную систему из Oracle), мы вернулись к резервной копии и отключили ее, IndexOptimizeи все вернулось в нормальное состояние.

Тем не менее, мы хотели бы понять, что IndexOptimizeотличается от «нормального», Index Rebuildкоторое могло бы вызвать это экстремальное снижение производительности, чтобы гарантировать, что мы избежим его, как только перейдем к производству. Будем весьма благодарны за любые предложения о том, что искать.

План выполнения оператора update, когда он медленный. т.е.
после IndexOptimize
фактический план выполнения (как можно скорее)

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

Мартин Бергстрем
источник

Ответы:

11

Я подозреваю, что у вас есть другая частота выборки, определенная между вашими двумя подходами обслуживания. Я полагаю, что скрипты Олы используют выборку по умолчанию, если вы не укажете @StatisticsSampleпараметр , который, по-вашему, сейчас не выглядит.

На данный момент это предположение, но вы можете проверить, какая частота выборки в настоящее время используется в вашей статистике, выполнив следующий запрос в вашей базе данных:

SELECT  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) AS TableName
    ,   col.name AS ColumnName
    ,   st.name AS StatsName
    ,   sp.last_updated
    ,   sp.rows_sampled
    ,   sp.rows
    ,   (1.0*sp.rows_sampled)/(1.0*sp.rows) AS sample_pct
FROM sys.stats st 
    INNER JOIN sys.stats_columns st_col
        ON st.object_id = st_col.object_id
        AND st.stats_id = st_col.stats_id
    INNER JOIN sys.columns col
        ON st_col.object_id = col.object_id
        AND st_col.column_id = col.column_id
    CROSS APPLY sys.dm_db_stats_properties (st.object_id, st.stats_id) sp
ORDER BY 1, 2

Если вы видите, что это происходит через 1 с (например, 100%), это ваша проблема. Может быть, попробуйте сценарии Ola снова, включая @StatisticsSampleпараметр с процентом, возвращаемым этим запросом, и посмотрите, решит ли это вашу проблему?


В качестве дополнительных подтверждающих доказательств этой теории XML плана выполнения показывает очень разные частоты выборки для медленного запроса (2,18233%):

<StatisticsInfo LastUpdate="2019-09-01T01:07:46.04" ModificationCount="0" 
    SamplingPercent="2.18233" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

По сравнению с быстрым запросом (100%):

<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555" 
    SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />
Джон Айсбренер
источник
@JoshDarnell LOL, это второй случай, когда вы нашли некоторую вспомогательную информацию о статистике в плане запросов, которую мне не удалось увидеть. Спасибо за редактирование!
Джон Айсбренер
Хаха, я забыл, что это был ты, Джон! Я обещаю, что не преследую тебя J
Джош Дарнелл
@JoshDarnell Я ценю дополнительные идеи, и это еще одно хорошее напоминание о том, что в планах выполнения так много информации, что вам просто не следует пропускать.
Джон Эйсбренер
Рад помочь! И да, есть вещи, которые я тоже пропускаю все время (меня сгорела статистика, поэтому я стремлюсь туда быстро посмотреть, что случилось).
Джош Дарнелл,
Спасибо за это объяснение, это была действительно проблема. Большинство статистических данных имели частоту дискретизации по умолчанию 2,2%, однако некоторые из них были созданы после миграции из Oracle с частотой дискретизации 100%. Кажется, что перестройка индекса по умолчанию сохранила 100%, но когда мы использовали IndexOptimize, он также применил к ним значение по умолчанию 2,2%. Применение параметра @StatisticsSample и повторный запуск запросов подтвердили, что именно это и стало причиной проблемы.
Мартин Бергстрем
5

Ответ Джона - правильное решение, это всего лишь дополнение к тому, какие части плана выполнения изменились, и пример того, как легко обнаружить различия с помощью обозревателя Sentry One Plan.

Заявление об обновлении, которое заняло 100 мс до того, как IndexOptimize заняло 78 000 мс после (с использованием идентичного плана)

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

Ухудшенная производительность

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

Два отсчета, более 35 секунд времени процессора и истекшего времени

Ожидаемая производительность

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

Намного лучше

Основное ухудшение дважды в этом запросе на обновление:

UPDATE SVALA.INGÅENDEANALYS
                           SET 
                              UPPDRAGAVSLUTAT = @NEW$AVSLUTAT
                        WHERE INGÅENDEANALYS.ID IN 
                           (
                              SELECT IA.ID
                              FROM 
                                 SVALA.INGÅENDEANALYS  AS IA 
                                    JOIN SVALA.INGÅENDEANALYSX  AS IAX 
                                    ON IAX.INGÅENDEANALYS = IA.ID 
                                    JOIN SVALA.ANALYSMATERIAL  AS AM 
                                    ON AM.ID = IA.ANALYSMATERIALID 
                                    JOIN SVALA.ANALYSMATERIALX  AS AMX 
                                    ON AMX.ANALYSMATERIAL = AM.ID 
                                    JOIN SVALA.INSÄNTMATERIAL  AS IM 
                                    ON IM.ID = AM.INSÄNTMATERIALID 
                                    JOIN SVALA.INSÄNTMATERIALX  AS IMX 
                                    ON IMX.INSÄNTMATERIAL = IM.ID
                              WHERE IM.UPPDRAGSID = SVALA.PKGSVALA$STRIPVERSION(@NEW$ID)
                      )

план выполнения этого запроса с пониженной производительностью

Расчетный план запроса для этого запроса на обновление имеет очень высокие оценки, когда производительность снижается:

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

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

Наибольшее влияние на производительность оказывают два скана и соединения с хэш-соответствием, приведенные ниже:

Фактическое сканирование на ухудшенной производительности # 1

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

Фактическое сканирование на ухудшенной производительности # 2

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


План выполнения этого запроса с ожидаемой производительностью

Когда вы сравниваете это с оценками (или фактическими данными) плана запроса с нормальной ожидаемой производительностью, различия легко заметить.

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

Кроме того, предыдущие два доступа к таблицам даже не произошли:

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

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

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

Вы не видите этого исключения в хеш-соединении, потому что входная информация build (top) сначала вставляется в хеш-таблицу. После этого в этой хэш-таблице проверяются нулевые значения, которые возвращают нулевые значения.

Рэнди Вертонген
источник
1
Спасибо за подробное описание планов, это очень помогло мне понять, почему возникла проблема. Я обязательно взгляну на Sentry One Plan Explorer, он выглядит очень полезным!
Мартин Бергстрем
@ MartinBergström Приятно слышать, спасибо за предоставление планов запросов и предоставление нам всей необходимой информации, о которой мы спрашивали в комментариях :). Лучшее в планере проводников - это то, что он бесплатный! Он также может работать изнутри ssms (щелкнув правой кнопкой мыши план выполнения и нажав «просмотр с помощью проводника плана»).
Рэнди Вертонген
1

Без дополнительной информации мы можем делать лишь слегка информированные удары в темноте, поэтому вам следует отредактировать вопрос, чтобы предоставить немного больше информации. Например, планы запросов для этого оператора обновления, для которого вы задали сроки, как до, так и после операций обслуживания индекса, поскольку планы могут отличаться из-за обновления статистики индекса ( https://www.brentozar.com/pastetheplan). / полезно для этого, вместо того, чтобы заполнять вопрос тем, что может быть огромным фрагментом XML, или давать скриншот, который не включает в себя некоторую соответствующую информацию, содержащуюся в плане).

Хотя два очень простых момента:

  1. Оптимизированный прогон определенно завершен? Если ваши тесты конкурируют с IO длительных перестроений индекса, это повлияет на время.
  2. Вы тестировали несколько раз? Если обновление основано на данных из запроса, который рассматривает много данных (а не просто `UPDATE TheTable SET ThisColumn = 'A Static Value'), то, возможно, эти данные обычно находятся в памяти, но были сброшены в который при первом запуске связанных запросов будет медленнее, чем обычно, из-за попадания на диск, а не из-за того, что нужные страницы уже находятся в пуле буферов в памяти.
Дэвид Спиллетт
источник
Спасибо, что нашли время ответить. Я обновил этот вопрос ссылками на pastetheplan. Оптимизация определенно завершилась, она работала около 1 часа за день до того, как возникли проблемы. Мы проводили тестирование несколько раз, и это фактически повлияло на две копии базы данных, работающие в двух разных средах тестирования одинаково. Оператор Update был просто самым простым примером, который я нашел, были затронуты многочисленные другие вставки и
Martin Bergström
Под «многократным» я имел в виду попытки обновлений несколько раз после изменения одного экземпляра индекса вместо того, чтобы запускать скрипт оптимизации индекса несколько раз независимо (хотя сам по себе это полезный способ проверки воспроизводимости результата). Если сбрасывание памяти является (или является частью) проблемой, то первые обновления от выбранных заполняют буферный пул, поэтому последующие могут быть быстрее из-за значительно уменьшенного ввода-вывода.
Дэвид
Извиняюсь, если мой ответ был неясен. Да, мы пробовали обновления несколько раз. Замедления произошли в базе данных, используемой тестировщиками для тестирования приложения, а также запросов и обновлений, которые выполнялись несколько раз в течение дня без повышения производительности.
Мартин Бергстрем