Оптимизация запросов к SQL базам данных

от 2020 - 08 - 26

Общие решения.

  • План и индекс иногда помогают.
  • Apply менять на Join и наоборот. Если взаимно заменяемы, то может сработать.
  • Все фильтры пробовать запихать внутрь джойнов/апплаев/with. Вообще все тяжелые фильтры вместе с выборкой можно запихивать в with.
  • Так же различные сложные конструкции (много операторов объединения), особенно на большом объеме(evn!) данных лучше разносить в несколько with и потом объединять.
  • Без хинтов работать ничего не будет.
  • Иногда чтобы работало быстро проще взять из таблицы, чем из вьюхи, в которой десять джойнов. Это плохо.
  • Запрос может не просить индекс, а вот часть его – да. Не всегда этот индекс будет нагребаться в общий план, но иногда легче становилось.
  • Еще немного подумать и сделать дополнительные фильтры – чем более ограничены выборки, тем меньше объем перелопачиваемых данных.
  • GetDate лучше сразу запихать в переменную, а не вызывать каждый раз. К тому же в SQL есть функция NOW(), которую потом можно привести к любому типу данных работы с датой или временем.
  • In – чаще всего зло. Чем больше объем, тем хуже. Лучше join.
  • In или exists – чисто эмпирически. Но если в in тяжелая конструкция, то запрос умрет.
  • Если есть в запросе OR, результат будет не скор.
  • Никаких *
  • Курсоры только в крайнем случае, скорее даже не для выборки а для модификации данных.
  • Запрос в подзапросе в подзапросе в подзапросе будет выполняться, выполняться, выполнятся и выполняться…
  • Универсальных скриптов не бывает, если есть возможность в зависимости от требований пользователя менять(упрощать) выборку, лучше иметь несколько запросов.
  • Есть запросы, которые нельзя оптимизировать до 5 секунд ввиду того, что они пользуют самые «ходовые таблички» и объем данных зашкаливает. Например, список нетрудоспособного населения. Такой запрос можно для начала сделать не таким кривым, каким он попал к нам в руки и запускать после рабочего дня раз… в месяц например, как того требуют.
  • У нас есть нагрузочный, можно на нем пробовать запускать и смотреть, что будет.
  • Если запрос висит, а план говорит что всё ок, то надо отрезать от запроса по-кусочкам до тех пор, пока не найдется слабое место и с ним уже можно работать. Если нет тонких мест и каждая итерация отрезания убавляет примерно равное количество времени, надо пересматривать логику.
  • Если на тестовой запрос с трудом успевает по таймингу, то на рабочей в пик нагрузки оно повиснет навсегда.
  • Запрос может быть нормальным, но на серваке случится флуктуация и он построит план на 50 гигабайт оперативы. Сбросить план.
  • Запрос может медленно работать на рабочей, если там одновременно 600 сессий, которые друг друга блокируют.
  • Очень часто даты фильтруются в самом последнем блоке where, после того как уже нагребается общая выборка. Это плохо. Надо по датам фильтровать самую первую выборку.

Индексы.

  • Соотношение — 1 поле для кучи индексов плохо влияет на производительность модификации данных, так как надо много индексов переделывать кроме самой таблицы.
  • Для часто меняемой по данным таблице плохо иметь много индексов, а для часто используемой в выборках вполне нормально.
  • Покрывающий (все поля?) индекс развеселит и самый мертвый запрос. SQL при нём табличку трогает минимум, но место на диске он захватит много и с изменениями данных будут проблемы.
  • Чем больше табличка, тем больше Fillfactor