Курсоры, как правило, не болезнь, а ее симптом: не используется подход, основанный на множестве (как упоминалось в других ответах).
Непонимание этой проблемы и просто вера в то, что ее устранение может решить «злой» курсор, может усугубить ситуацию.
Например, замена итерации курсора другим итеративным кодом, таким как перемещение данных во временные таблицы или переменные таблиц, для циклического перемещения по строкам следующим образом:
SELECT * FROM @temptable WHERE Id=@counter
или
SELECT TOP 1 * FROM @temptable WHERE Id>@lastId
Такой подход, как показано в коде другого ответа, значительно ухудшает ситуацию и не устраняет исходную проблему. Это анти-паттерн, который называется программирование культа грузов : не знать, ПОЧЕМУ что-то плохо, и, следовательно, реализовывать что-то худшее, чтобы избежать этого! Недавно я изменил такой код (используя #temptable и без индекса для identity / PK) обратно на курсор, и обновление чуть более 10000 строк заняло всего 1 секунду вместо почти 3 минут. Все еще не хватает подхода, основанного на множестве (будучи меньшим злом), но лучшее, что я мог сделать в этот момент.
Другим признаком этого недостатка понимания может быть то, что я иногда называю «болезнью одного объекта»: приложения баз данных, которые обрабатывают отдельные объекты через слои доступа к данным или объектно-реляционные сопоставители. Обычно код такой:
var items = new List<Item>();
foreach(int oneId in itemIds)
{
items.Add(dataAccess.GetItemById(oneId);
}
вместо
var items = dataAccess.GetItemsByIds(itemIds);
Первый обычно заполняет базу данных множеством SELECT, по одному обходу в каждом, особенно когда в игру вступают деревья / графики объектов и возникает печально известная проблема SELECT N + 1.
Это прикладная сторона непонимания реляционных баз данных и подхода, основанного на множестве, точно так же, как курсоры при использовании процедурного кода базы данных, такого как T-SQL или PL / SQL!