Плюсы и минусы использования курсора (на сервере SQL) - PullRequest
7 голосов
/ 17 февраля 2012

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

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

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

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

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

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

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

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

Ответы [ 5 ]

11 голосов
/ 17 февраля 2012

Есть несколько сценариев, в которых курсоры на самом деле работают лучше, чем основанные на множестве эквиваленты. Постоянные итоги - это то, что всегда приходит на ум - поищите слова Ицик по этому поводу (и не обращайте внимания на любые слова, связанные с 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 для выполнения групповой конкатенации не выполняет скрытую операцию курсора. Глядя на план во многих случаях покажет правду.

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

ОБНОВЛЕНИЕ 2013-07-25

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

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

Какое влияние могут оказать различные параметры курсора?

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

6 голосов
/ 17 февраля 2012

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

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

3 голосов
/ 17 февраля 2012

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

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

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

0 голосов
/ 21 августа 2013

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

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

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

Более подробное объяснение см. В следующих статьях:

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

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

Правда о курсорах: Часть III

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

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

0 голосов
/ 18 февраля 2012

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

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