Плюсы и минусы использования курсора (в SQL server)

Я задал здесь вопрос использование курсора в базах данных OLTP (SQL server)

где люди ответили, что курсоры никогда не должны использоваться.

Я чувствую, что курсоры - очень мощные инструменты, которые предназначены для использования (я не думаю, что Microsoft поддерживает курсоры для плохих разработчиков).Предположим, у вас есть таблица, в которой значение столбца в строке зависит от значения того же столбца в предыдущей строке. Если это один раз back end процесс, не думаете ли вы использование курсора было бы приемлемым выбором?

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

1>однократный обратный процесс для очистки плохих данных, который завершает выполнение в течение нескольких минут. 2 > пакетные процессы, которые выполняются один раз в течение длительного периода времени (примерно раз в год). Если в приведенных выше сценариях нет видимого напряжения на другом процессы, не было бы неразумно тратить дополнительные часы на написание кода, чтобы избежать курсоров? Другими словами, в некоторых случаях время разработчика важнее, чем производительность процесса, который почти не влияет ни на что другое.

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

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

пожалуйста, дайте мне знать ваши мысли.

5 ответов


существует несколько сценариев, в которых курсоры фактически работают лучше, чем эквиваленты на основе набора. Запуск итогов - это тот, который всегда приходит на ум, - ищите слова Ицика на этом (и игнорируйте любые, которые включают SQL Server 2012, который добавляет новые оконные функции, которые дают курсорам работать за свои деньги в этой ситуации).

одна из больших проблем людей имеет с курсорами что они выполняют медленно, они используют временное хранение, ЕТК. Частично это связано с тем, что по умолчанию синтаксис-это глобальный Курсор со всеми видами неэффективных параметров по умолчанию. В следующий раз вы делаете что-то с курсором, который не должен делать такие вещи, как UPDATE...WHERE CURRENT OF (которого я смог избежать всю свою карьеру), дайте ему справедливую встряску, сравнив эти два варианта синтаксиса:

DECLARE c CURSOR 
    FOR <SELECT QUERY>;

DECLARE c CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY
    FOR <SELECT QUERY>;

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

многие люди думают, что методология не является курсором, потому что она не говорит DECLARE CURSOR. Я видел, как люди утверждают, что цикл while быстрее, чем курсор (который, надеюсь, я развеял здесь) или что с помощью FOR XML PATH для выполнения конкатенации группы не выполняется скрытая операция курсора. Просмотр плана во многих случаях покажет правду.

во многих случаях курсоры используются там, где более уместно использовать set-based. Но есть много допустимых случаев использования, когда эквивалент на основе набора намного сложнее написать, для оптимизатора, чтобы создать план для обоих, или невозможно (например, задачи обслуживания, где вы перебираете таблицы для обновления статистики, вызов хранимой процедуры для каждого значения в результат и т. д.). То же самое верно для многих больших многоплатформенных запросов, где план становится слишком чудовищным для обработки оптимизатором. В этих случаях может быть лучше сначала сбросить некоторые промежуточные результаты во временную структуру. То же самое относится к некоторым эквивалентам курсоров на основе наборов (например, запуск итогов). Я также писал о другом способе, где люди почти всегда думают инстинктивно использовать цикл / курсор while, и есть умные альтернативы на основе набора, которые намного лучше.

2013-07-25 обновление

просто хотел добавить несколько дополнительных сообщений в блоге, которые я написал о курсорах, какие параметры вы должны использовать, если вы do должны использовать их и использовать запросы на основе набора вместо циклов для создания наборов:

лучшие подходы для запуска итогов-обновлено для SQL Server 2012

какое воздействие может оказать другой курсор варианты есть?

создать набор или последовательность без циклов:[Часть 1] [Часть 2] [Часть 3]


проблема с курсорами в SQL Server заключается в том, что движок основан на наборе внутри, в отличие от других СУБД, таких как Oracle, которые основаны на курсоре внутри. Это означает, что при создании курсора в SQL Server необходимо создать временное хранилище и скопировать набор результатов на основе набора во временное хранилище курсора. Вы можете понять, почему это было бы дорого сразу, не говоря уже о какой-либо обработке строк, которую вы могли бы делать поверх самого курсора. Этот суть в том, что обработка на основе набора более эффективна, и часто ваша операция на основе курсора может быть выполнена лучше с помощью CTE или temp-таблицы.

Это, как говорится, есть случаи, когда курсор, вероятно, приемлем, как вы сказали для одноразовых операций. Наиболее распространенное использование, которое я могу придумать, - это план обслуживания, где вы можете перебирать все базы данных на сервере, выполняющем различные задачи обслуживания. Пока вы ограничиваете свое использование и не проектируете целое приложения вокруг обработки RBAR (строка за строкой), вы должны быть в порядке.


В общем курсоры-это плохо. Однако в некоторых случаях более практично использовать курсор, а в некоторых-еще быстрее. Хорошим примером является курсор через таблицу контактов, отправляющий электронные письма на основе некоторых критериев. (Не открывать вопрос, если отправка электронной почты из вашей СУБД-хорошая идея - давайте просто предположим, что это для проблемы.) Нет никакого способа написать этот набор на основе. Вы можете использовать некоторые хитрости, чтобы придумать решение на основе набора для создания динамического SQL, но реальные решения не существует.

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

во всех случаях вам нужно сбалансировать усилия, связанные с разработкой более быстрого решения. Если никому нет дела, если процесс выполняется за 1 минуту или за один час, используйте то, что быстрее всего выполняет работу. Если вы просматриваете набор данных, который растет со временем, как таблица [orders], постарайтесь держаться подальше от курсор, если это возможно. Если вы не уверены, выполните тест производительности, сравнивающий базу курсоров с решением на основе набора на нескольких существенно разных размерах данных.


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


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

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

Итак, чтобы повысить производительность с помощью курсора, измените тип используемого курсора. Что-то я не знаю, если вы не укажите, какой тип курсора вы объявляете, вы получите динамический оптимистический тип по умолчанию, который является самым медленным для производительности, потому что он выполняет много работы под капотом. Однако, объявив курсор как другой тип, скажем, статический курсор, он имеет очень хорошую производительность.

посмотреть эти статьи для более полного объяснения:

Правда О Курсорах: Часть I

Правда О Курсорах: Часть II

правда о Курсорах: Часть III

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

SQL Server оптимизирован для запуска подхода на основе набора. Вы пишете запрос, чтобы вернуть результирующий набор данных, например join on tables для пример, но механизм выполнения SQL Server определяет, какое соединение использовать: объединение слиянием, вложенный цикл или хэш-соединение. SQL Server определяет наилучший возможный алгоритм соединения на основе участвующих столбцов, тома данных, структуры индексирования и набора значений в участвующих столбцах. Таким образом, использование подхода, основанного на множестве, обычно является лучшим подходом в производительности по сравнению с процедурным подходом курсора.