Что быстрее в SQL, цикле while, рекурсивной хранимой процедуре или курсоре?

Что быстрее в SQL, цикле while, рекурсивной хранимой процедуре или курсоре? Я хочу оптимизировать производительность в нескольких местах хранимой процедуры. Код, который я оптимизирую, форматирует некоторые строки для вывода в файл.


person Casey    schedule 11.06.2010    source источник
comment
Вероятно, это зависит от того, какую базу данных вы используете...   -  person Artelius    schedule 11.06.2010
comment
зависит от того, что внутри. курсор — это способ перемещения по строкам, а пока — структура управления. забудьте о рекурсии, глубина стека ограничена 32.   -  person Andrey    schedule 11.06.2010
comment
Я вывожу в файл из sql. Я не знаю, как это сделать, ориентированный на множество.   -  person Casey    schedule 11.06.2010
comment
Какая версия SQL — Oracle, SQLServer, MYSQL, Postgres и т. д.?   -  person    schedule 11.06.2010
comment
С рекурсией вы можете достичь максимального уровня рекурсии. И если я помню, для Sql Server это максимум 32 рекурсии.   -  person Pierre-Alain Vigeant    schedule 11.06.2010


Ответы (7)


Я предполагаю, что вы используете SQL Server.

Прежде всего, как кто-то сказал в заявлениях, рекурсивные хранимые процедуры, хотя и возможны, не являются хорошей идеей в SQL Server из-за размера стека. Итак, любая глубоко рекурсивная логика сломается. Однако, если у вас в лучшем случае 2-3 уровня вложенности, вы можете попробовать использовать рекурсию или использовать CTE, который также немного рекурсивен (SQL Server 2005 и выше). Как только вам удастся разобраться с CTE, это станет чрезвычайно полезной техникой. Я не измерял, но у меня никогда не было проблем с производительностью в нескольких местах, где я использовал CTE.

С другой стороны, курсоры сильно снижают производительность, поэтому я (и половина интернета) рекомендовал бы не использовать их в часто вызываемом коде. Но поскольку курсоры представляют собой скорее классическую структуру программирования, похожую на foreach в C#, некоторым людям проще смотреть, понимать и поддерживать код SQL, который использует курсоры для манипулирования данными, чем какое-то запутанное чудовище SQL с множественным внутренним выбором, поэтому не самая плохая идея использовать их в коде, который будет вызываться время от времени.

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

Подводя итог, если бы мне пришлось создать сложную хранимую процедуру, где производительность имеет первостепенное значение, я бы попробовал:

  1. Использование подхода на основе набора (внутренний выбор, объединение, объединение и т. д.)
  2. Использование CTE (понятно и понятно для опытного пользователя, немного сомнительно для новичка)
  3. Использование операторов управления потоком (if, while...)
  4. Использование курсоров (процедурный код, простой для понимания)

в этой последовательности.

Если код будет использоваться гораздо реже, я, вероятно, перенесу 3 и 4 перед 1 и 2, но, опять же, только для сложных сценариев, в которых используется много таблиц и много отношений. Конечно, YMMV, поэтому я бы протестировал любую процедуру, которую я делаю, в реальном сценарии, чтобы на самом деле измерить производительность, потому что мы можем говорить до посинения о том, что быстро, а что медленно, но пока вы получаете реальные измерения, невозможно сказать, улучшают ли изменения ситуацию или ухудшают ее.

И, не забывайте, скорость кода зависит от скорости ваших данных. Ничто не заменит хорошую индексацию.

person SWeko    schedule 11.06.2010

Г) Ничего из вышеперечисленного.

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

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

person Tom H    schedule 11.06.2010
comment
Мне нужно вывести в текстовый файл. Я не уверен, как выводить, кроме как итеративно, так как мне нужно отформатировать поля перед выводом в файл. - person Casey; 11.06.2010
comment
используйте bcp и queryout, сделайте форматирование в запросе, это предполагает сервер sql, большинство rdbms имеют аналогичную вещь - person SQLMenace; 11.06.2010

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

person SQLMenace    schedule 11.06.2010

Рекурсивная хранимая процедура, вероятно, будет самой медленной, а цикл и курсоры не исключают друг друга. Операции с курсором довольно быстрые (IME), но я когда-либо использовал их только из внешнего (не SQL) кода. Другие плакаты верны, если вы можете выполнять обработку в соответствии с набором, вы получите наилучшую производительность.

person TMN    schedule 11.06.2010
comment
Это может быть единственный пост, который действительно отвечает на заданный вопрос и дает правильный ответ в большинстве случаев. В порядке производительности это будет: 1. Курсор быстрой перемотки вперед (большинство курсоров могут быть FF), 2. Пока цикл, 3. Рекурсивный SP. (И Set Ops будет равен 0 по этой шкале.) - person TTT; 02.01.2015

Взгляните на Курсоры и как их избежать. заменить курсоры операциями на основе SET

person SQLMenace    schedule 11.06.2010

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

Правда о курсорах

person james lewis    schedule 11.06.2010

Вы еще не знаете, но хотите прочитать эту книгу.

https://rads.stackoverflow.com/amzn/click/com/0596514972

person Marco Mariani    schedule 11.06.2010