После массовой загрузки данных прежний запрос резко замедлился, хотя индексы не менялись. Какой механизм статистики мог привести к выбору неудачного плана?
Оптимизатор мог использовать устаревшую статистику и неверно оценить количество строк, подходящих под условие. Из-за этого он выбрал план, подходящий для прежнего распределения данных, но неэффективный для нового: например, последовательный просмотр вместо индексного доступа или вложенные циклы вместо соединения хешированием.
Индекс при этом может оставаться полностью исправным. Проблема возникает не в структуре индекса, а в недостаточной информации оптимизатора о текущем объёме и распределении данных.
Оптимизатор SQL-запросов появился как способ автоматически выбирать порядок соединений, методы доступа к таблицам и алгоритмы соединения. Перебирать все варианты выполнения и точно просматривать данные перед каждым запросом слишком дорого, поэтому оптимизатор принимает решение на основе статистики.
Статистика обычно содержит сведения о числе строк, количестве различных значений, распределении значений и иногда гистограммы. Эти данные позволяют оценивать селективность условий без полного чтения таблицы.
После массовой вставки, удаления или изменения данных прежняя статистика может перестать отражать реальное распределение. Особенно опасна ситуация, когда появились новые значения, изменилось соотношение частых и редких значений или резко вырос размер таблицы.
Оптимизатор сравнивает стоимость планов на основе оценочного количества строк. Если оценка сильно ошибочна, он может выбрать стратегию, которая теоретически дешевле, но фактически выполняет большое число лишних операций. Рост времени запроса бывает непропорциональным объёму изменения данных.
Статистика влияет прежде всего на оценку кардинальности — прогноз числа строк после фильтрации, соединения или группировки. Например, оптимизатор может ожидать несколько строк и выбрать вложенные циклы с индексным поиском, хотя фактически условию соответствуют миллионы строк. Повторный индексный доступ в таком случае становится дороже последовательного чтения.
Обновление статистики позволяет оптимизатору пересчитать эти оценки. Но оно не гарантирует идеальный план: распределение может быть сильно неравномерным, корреляции между столбцами могут быть неизвестны, а статистика может быть собрана по выборке. Разные СУБД по-разному определяют состав статистики, частоту её обновления и доступные гистограммы.
Диагностика должна начинаться со сравнения оценочного и фактического числа строк в плане выполнения. Если расхождение велико на одном из узлов плана, нужно проверить актуальность статистики, изменение распределения данных и наличие статистики по значимым столбцам.
Принудительная фиксация удачного плана может временно снизить ущерб, но скрывает первопричину и может устареть после следующего изменения объёма или распределения данных. Перестроение индекса без обновления статистики не обязательно устранит ошибку оценки, а бездоказательное увеличение числа индексов повышает стоимость записи и обслуживания.
В таблицу событий ежедневно загружались данные нового крупного клиента. До загрузки фильтр по идентификатору клиента возвращал мало строк, и план с вложенными циклами был эффективен. После загрузки доля этого клиента стала значительной, но статистика ещё отражала прежнее распределение, поэтому оптимизатор продолжил считать выборку маленькой.
Рассматривались три варианта. Перестроение индекса могло помочь при физической деградации структуры, но не исправляло неверную оценку распределения. Принудительная фиксация плана быстро стабилизировала запрос, однако создавала зависимость от текущего объёма данных. Ожидание автоматического обслуживания статистики не давало предсказуемого времени восстановления.
Выбрали обновление статистики после массовой загрузки и проверку фактического плана на типичных значениях параметра. После этого оптимизатор стал выбирать разные планы для малых и крупных выборок там, где это поддерживалось СУБД, либо был настроен другой устойчивый вариант. Запрос ускорился не из-за изменения индекса, а из-за исправления исходных оценок.
Нет. Обновление статистики полезно, если проблема вызвана устаревшими оценками, но оно не устраняет отсутствие индекса, неудачную форму запроса, блокировки или чрезмерную передачу данных. После обновления нужно проверить план и сравнить оценочное количество строк с фактическим.
Распределение значений может быть неравномерным: одни значения встречаются редко, другие — очень часто. Усреднённая оценка подходит не всем значениям, особенно если статистика не описывает эту неравномерность достаточно подробно. Поэтому параметризованный запрос иногда сталкивается с проблемой чувствительности плана к значению параметра: план, удачный для редкого значения, оказывается плохим для частого.
Статистика может быть неполной, собранной по выборке или не учитывать корреляцию нескольких столбцов. Кроме того, ошибка может возникать на другом узле плана, например при оценке результата соединения, а не фильтрации. Нужно анализировать весь план выполнения, включая порядок соединений, фактические и оценочные строки, сортировки, обращения к диску и влияние параметров.