Рефакторинг «экстремальных» SQL-запросов - PullRequest
3 голосов
/ 26 ноября 2008

У меня есть бизнес-пользователь, который попробовал свои силы в написании собственного SQL-запроса для отчета о статистике проекта (например, количество задач, этапов и т. Д.). Запрос начинается с объявления временной таблицы из 80+ столбцов. Затем существует почти 70 операторов UPDATE для временной таблицы в более чем 500 строках кода, каждая из которых содержит свой небольшой набор бизнес-правил. Он заканчивается SELECT * из временной таблицы.

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

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

Ответы [ 11 ]

5 голосов
/ 26 ноября 2008

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

Когда вы решите это исправить, проверьте, есть ли один оператор, вызывающий большинство ваших проблем со скоростью ... опечатайте и исправьте его.

Если проблема скорости превышает все операторы, и вы можете объединить все это в один SELECT, это, вероятно, сэкономит ваше время. Однажды я конвертировал такой процесс (не так много обновлений) в SELECT, и время его запуска возросло с 3 минут до 3 секунд (ни черта ... я не мог в это поверить) Кстати, не пытайтесь сделать это, если некоторые данные поступают со связанного сервера.

Если вы не хотите или не можете этого делать по какой-либо причине, то вы можете настроить существующий процесс. Вот некоторые вещи, на которые я бы посмотрел:

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

  2. Настройте исходную ВСТАВКУ, чтобы вставить как можно больше столбцов. Вероятно, есть некоторые обновления, которые вы можете устранить, выполнив это.

  3. Индексируйте временную таблицу перед запуском обновлений. Не создавайте индексы ни для одного из столбцов, на которые нацелены операторы обновления, до тех пор, пока они не будут обновлены.

  4. Сгруппируйте свои обновления, если ваши таблицы и группировки позволяют это. 70 обновлений - это довольно мало для всего лишь 80 столбцов. Похоже, что для этого есть возможность.

Удачи

2 голосов
/ 22 января 2009

Есть почти 70 ОБНОВЛЕНИЕ заявления к таблице времен почти 500 строк кода, каждый содержать свой собственный маленький набор бизнес правила. Это заканчивается SELECT * из временной таблицы.

На самом деле это звучит так, как если бы за ним следили и понимали его достаточно хорошо, каждый оператор обновления выполняет одну функцию в таблице с определенной целью и набором бизнес-правил. Я думаю, что поддерживать процедуры из 500 строк кода с одним или несколькими операторами выбора, которые делают «все», построено из 15 или около того объединений, а также с инструкциями case и т. Д., Разбросанными повсеместно, гораздо сложнее поддерживать. Хотя это улучшит производительность ..

С SQL возникает некоторая дилемма: написание четкого и лаконичного кода (с использованием нескольких обновлений, создания функций и т. Д.) Всегда оказывает большое негативное влияние на производительность. Попытка сделать все сразу, что считается плохой практикой в ​​других языках программирования, по-видимому, является ядром языков, ориентированных на множество.

2 голосов
/ 26 ноября 2008

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

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

2 голосов
/ 26 ноября 2008

Первое, что я хотел бы сделать, это убедиться, что периодически выполняется задание на обслуживание активного индекса. Если нет, восстановите все существующие индексы или, если это невозможно, хотя бы обновите статистику.

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

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

РЕДАКТИРОВАТЬ: Если вы собираетесь понизить голосование, пожалуйста, оставьте комментарий, почему.

1 голос
/ 11 июля 2010

Перепишите возможно. Одним из аппаратных решений было бы убедиться, что временная таблица вашей базы данных работает на «быстром» диске, возможно, на твердотельном диске (SSD), или может управляться всеми в памяти.

Полагаю, это «решение» было разработано кем-то, кто разбирается в электронных таблицах и зависит от него, кем-то, кто не очень разбирается в «нормализованных» базах данных - как создавать и заполнять таблицы для хранения данных для целей отчетности что-то, что, возможно, программное обеспечение BI Business Intelligence, может использоваться с изощренностью и все же быть адаптируемым.

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

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

Могут ли запросы, используемые для условий обновления, быть разложены в виде статических «представлений», которые, в свою очередь, могут использоваться несколькими операторами обновления? Представления могут хранить в памяти данные / строки запросов, к которым часто обращаются. Возможна настройка производительности при определении того, сколько данных обновления может быть отложено до оптимального принятия.

Возможно, стоит оценить, можно ли использовать триггеры для замены последовательности обновления пакетного задания. Вы не говорите, из каких таблиц получены данные ... которые могут помочь в принятии решений. Я не знаю, есть ли у вас возможность добавить триггеры в таблицы базы данных, из которых собираются данные. Если это так, добавление нескольких триггеров к нескольким таблицам не сильно снизит общую производительность системы, но может сэкономить большую часть времени в процессе обновления. Вы можете попробовать заменить операторы обновления по одному триггерами и посмотреть, будут ли результаты такими же, как раньше. Создайте аналогичную временную таблицу, основанную на том же процессе обновления, затем тщательно проверьте, могут ли триггеры подачи обновлений в временную таблицу заменить отдельные операторы обновления. Возможно, у вас есть своего рода приложение «Хранилище данных». Может быть полезно рассмотреть, как настроить «звездную» схему таблиц для хранения обобщенных бизнес-данных для отчетности.

Создание всеобъемлющего и кэшированного «представления», которое обновляется с помощью запросов один раз в день, что отражает обновления, возможно, является еще одним подходом к исследованию.

1 голос
/ 26 ноября 2008

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

Посмотрите на 70 операторов обновления. Можно ли объединить любой из них? Если человек, который пишет, не использовал отчеты CASE, возможно, можно будет сделать меньше заявлений.

Другие очевидные вещи, на которые стоит обратить внимание - исключите любые курсоры, замените любые подзапросы на объединения с таблицами или производными таблицами.

1 голос
/ 26 ноября 2008

Если это отчет, генерирующий хранимую процедуру, как часто она запускается? Если необходимо запускать его только один раз в день и запускать ночью, на сколько проблема в производительности?

Если это не так, я бы порекомендовал быть осторожным в вашем выборе, чтобы переписать его, потому что есть шанс, что вы можете испортить свои цифры.

Также это звучит как то, что нужно добавить в пакет служб SSIS, создав новую постоянную таблицу с результатами, поэтому ее нужно запускать только один раз.

Надеюсь, это имеет смысл

1 голос
/ 26 ноября 2008

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

0 голосов
/ 26 ноября 2008

Я бы переписал его с нуля.

Вы говорите, что понимаете, что он должен делать, поэтому это не должно быть так сложно. И я держу пари, что требования к этому коду будут постоянно меняться, поэтому, если вы не переписываете его сейчас, то в конечном итоге вы сможете сохранить какого-то ужасного монстра

0 голосов
/ 26 ноября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...