SQL Cursors... Какие-либо варианты использования, которые вы бы защитили?

Пойду первым.

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

Есть также случаи, когда курсоры просто превосходят, потому что оптимизатор недостаточно умен. В этих случаях либо есть метаинформация в вашей голове, которая просто не отображается оптимизатору через индексы или статистику по таблицам, или код настолько сложный, что объединения (и, как правило, повторное объединение) просто могут Оптимизированы так, как вы можете визуализировать их с помощью курсора. В SQL Server 2005 я считаю, что CTE, как правило, делают этот код намного проще в коде, но насколько оптимизатор также считает их более простыми, трудно понять - сводится к сравнению плана выполнения с тем, как вы думаете, что это можно сделать наиболее эффективно и сделать вызов.

Общее правило - не используйте курсор, если это необходимо. Но когда это необходимо, не делайте себе трудного времени.

Ответ 3

Существует много разных поведение курсора.

  • STATIC vs KEYSET vs DYNAMIC
  • SCROLL vs FORWARD ONLY vs FAST FORWARD
  • INSENSITIVE или нет
  • ОПТИМИЗИРОВАТЬ ИЛИ ПРОЧИТАТЬ ТОЛЬКО или нет
  • LOCAL vs GLOBAL (по крайней мере, это легко)

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

Итак, я никогда этого не делаю.

Вместо этого, когда я чувствую желание перебрать что-то в T-SQL... Я загружаю его в таблицу переменных, что-то вроде курсора LOCAL STATIC SCROLL... за исключением того, что его можно индексировать и объединить ( edit: и недостатком предотвращения использования parallelism).

Ответ 4

В чистой среде SQL я предпочел бы избегать курсоров, как вы предлагаете. Но как только вы переходите на процедурный язык (например, PL/SQL), существует ряд применений. Например, если вы хотите получить определенные строки и хотите "сделать" что-то более сложное, чем обновить их с ними.

Ответ 5

Очень редко вы получаете операцию, которая нуждается в курсоре, но в T-SQL она довольно редка. Столбцы или последовательности Identity (int) упорядочивают вещи в рамках заданных операций. Агрегации, в которых расчеты могут меняться в определенных точках (например, накопление требований с нуля до предела или избыточной точки), по сути, являются процедурами, поэтому они являются кандидатами на курсор.

Другие кандидаты были бы по сути процедурными, такими как цикл в таблице конфигурации и генерация и выполнение ряда запросов.

Ответ 6

Наряду с тем, что David B сказал, я тоже предпочитаю подход loop/table.

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

В этом случае лучше всего сделать обновление в "кусках", возможно, 1 миллион или 10 миллионов строк за раз. Это помогает свести использование ресурсов к минимуму и позволяет одновременное использование машины для максимизации при обновлении этого миллиарда строк. Здесь может быть лучше всего зацикленный/раздробленный подход. Обновления в миллиардах строк на устройствах, отличных от звездных, как правило, вызывают проблемы.

Ответ 7

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

Запуск итогов, как обсуждается другими, может быть быстрее.

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

Ответ 8

Ну, одна операция, где курсоры лучше, чем наборы, - это вычисление текущей и аналогичной вещи.

Ответ 9

Использование курсора обычно является признаком того, что вы делаете в базе данных, что должно быть сделано в приложении. Как говорили другие, курсоры, как правило, необходимы, когда хранимая процедура вычисляет текущие итоги или когда вы генерируете код и/или метапрограммирование.

Но почему вы делаете такую ​​работу в хранимой процедуре в первую очередь? Это действительно лучшее использование вашего сервера баз данных? Правильно ли используется T-SQL для генерации кода?

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

Ответ 10

Если таблица по какой-либо причине не индексируется, курсор будет быстрее, чем другие методы итерации по таблице. Я нашел эту информацию в этом сообщении в блоге о курсорах в SQL Server в прошлом году.

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

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