Запрос настроек 101
Не существует волшебной серебряной пули для настройки запросов, хотя я могу дать вам несколько советов и подсказок. Первое, что нужно сделать, это понять, что на самом деле происходит за кулисами. Получите хорошую внутреннюю книгу, например, «Путеводитель третьего гуру».
Плохо выполняющиеся запросы обычно бывают двух основных типов: транзакционные запросы, которые занимают слишком много времени, и шлифовальные пакетные задания (или отчеты), которые занимают слишком много времени. Один хороший признак запроса с чем-то не так - это один элемент в плане запроса, занимающий 99% времени.
Транзакционные запросы
В большинстве случаев плохо выполняемый транзакционный запрос является одной из нескольких вещей:
Отсутствующий индекс. Вы можете увидеть это в плане запроса - просмотр таблицы больших таблиц в соединении, который должен быть очень избирательным (т.е. возвращать несколько строк).
Запрос не может использовать индекс. Если у вас есть условия ИЛИ в предложении where, объединяет вычисленное значение или какой-либо другой элемент в запросе, который не может быть обработан с помощью sarg, то вам может потребоваться переписать запрос. Вкратце, sargs - это предикаты запросов, которые могут использовать индексы для удаления строк. Логическое «И», равенство и неравенство (>,> =, <, <= и! =) - все это может быть саргвируемым. ИЛИ традиционно не умеет саргить. Тем не менее, вы часто можете переводить OR в предикаты, пригодные для sarg, путем преобразования смысла из конструкций типа OR в NOT (foo и not bar).
Неэффективные предикаты. Например, если у вас есть where in
ссылка на вложенный подзапрос, посмотрите, можно ли его перезаписать как where exists
или как объединение. Это может привести к более эффективным планам запросов, и вот другие стандартные переписывания, которые вы также можете попробовать. Опять же, руководства Гуру и другие по этому вопросу являются хорошей отправной точкой.
Пакетные запросы
Пакетные запросы более сложны и имеют разные проблемы с настройкой. Некоторые советы:
Индексирование. Это может иметь большое значение по той же причине, что и для транзакционных запросов. Часто хорошим признаком отсутствия индекса является длительная операция шлифования (99% плана запроса), которая, кажется, не перебивает машину.
Временные столы. Возможно, вам будет удобнее разбить запрос на несколько запросов, заполняющих временные таблицы. Более крупные запросы дают оптимизатору больше возможностей для ошибок, хотя это не та проблема, которая была раньше. Создайте временные таблицы, так select into
как эта операция минимально регистрируется (намного меньше операций регистрации), что уменьшает нагрузку ввода-вывода.
Обратите внимание, что временные таблицы в базе данных tempdb имеют ту же структуру данных, которую оптимизатор использует для хранения промежуточных результатов объединения, поэтому за это не снижается производительность. Вы также можете создать индекс (включая кластеризованные и охватывающие индексы) для временной таблицы, что может повысить производительность запросов, читающих ее, по тем же причинам, по которым они улучшают запросы к статическим таблицам.
Не переусердствуйте с временными таблицами, так как они могут усложнить поиск по запросу. Для небольших таблиц в хранимой процедуре проверьте, помогают ли переменные таблицы. Это структура данных в памяти, поэтому они могут быть выигрышем в производительности.
Кластерные и покрывающие индексы. Это может повысить производительность запроса, поскольку они устанавливают локальность ссылок на диске на основе некоторого столбца группировки. Кластерный индекс может существенно повлиять на производительность пакетного задания.
Неэффективные предикаты. Это может вызвать проблемы с sargs и другими подоптимизациями во многом так же, как и с транзакционными запросами.
Таблица сканирования ваш друг. Вопреки распространенному мнению, сканирование таблицы не является по своей сути злом. Обычно они являются признаком чего-то неправильного в транзакционном запросе, но часто они являются наиболее эффективным способом выполнения крупномасштабной операции. Если вы делаете что-то с несколькими процентами строк в таблице, сканирование таблицы часто является наиболее эффективным способом покрытия таблицы.
Вложенные циклы включаются. Посмотрите, что оптимизатор делает с обеих сторон объединения. Это может быть неэффективно, если вы (например, таблица сканирует две большие таблицы по обе стороны от объединения вложенных циклов. Рассмотрите возможность использования кластерных индексов или order by
попыток изменить операцию на объединение слиянием или подсказку для продвижения хеш-объединения, если одна сторона достаточно маленький, чтобы сделать это с.
запирающий
Блокировка также может вызвать проблемы с производительностью. Если ваша система работает плохо под нагрузкой, посмотрите на профилировщик и счетчики perfmon, связанные с блокировками, и проверьте, есть ли какие-либо существенные конфликты. sp_who2
в результирующем наборе есть столбец BlkBy, который покажет, заблокирован ли запрос и что его блокирует. Кроме того, профили с событиями «граф взаимоблокировок» (если у вас есть запросы взаимоблокировки) и события, связанные с блокировкой, могут быть полезны для устранения проблем блокировки.