Почему люди так сильно ненавидят курсоры SQL? [закрытый]
Я могу понять желание избежать использования курсора из-за накладных расходов и неудобств, но похоже, что есть какая-то серьезная курсор-фобия-мания, когда люди идут на большие расстояния, чтобы избежать использования одного.
например, один вопрос спросил, Как сделать что-то явно тривиальное с курсором и принятый ответ предложил использовать рекурсивный запрос common table expression (CTE) с рекурсивной пользовательской функцией, хотя это ограничивает число строк, которые могут быть обработаны до 32 (из-за ограничения рекурсивного вызова функции в sql server). Это поражает меня как ужасное решение для долговечности системы, не говоря уже о огромных усилиях, чтобы избежать использования простого курсора.
в чем причина такого уровня безумной ненависти? Может быть, какой-то "известный авторитет" издал фетву против курсоров? Неужели в сердце курсоров таится какое-то невыразимое зло, которое развращает нравственность детей или что-то в этом роде?
вопрос Вики , больше интересует ответ, чем представитель.
Другая Информация:
ускоренная перемотка курсоров SQL Server
EDIT: позвольте мне быть более точным: я понимаю, что курсоры не должны использоваться вместо обычных реляционных операций; это без проблем. То, что я не понимаю, - это люди, которые уходят с дороги, чтобы избежать курсоров, таких как у них есть вши или что-то еще, даже когда курсор является более простым и/или более эффективным решением. Меня сбивает с толку иррациональная ненависть, а не очевидная техническая эффективность.
14 ответов:
"накладные расходы" с курсорами-это просто часть API. Курсоры-это то, как части СУБД работают под капотом. Часто
CREATE TABLEиINSERTестьSELECTоператоры, и реализация является очевидной внутренней реализацией курсора.использование высокоуровневых "операторов на основе наборов" связывает результаты курсора в один результирующий набор, что означает меньшее количество API взад и вперед.
курсоры предшествуют современным языкам, которые предоставляют первоклассные коллекции. Старый C, COBOL, Фортран и др., пришлось обрабатывать строки по одному, потому что не было понятия "коллекция", которая могла бы широко использоваться. Java, C#, Python и др., имеют первоклассные структуры списков, содержащие результирующие наборы.
Медленный Вопрос
в некоторых кругах реляционные соединения являются тайной, и люди будут писать вложенные курсоры, а не простое соединение. Я видел поистине эпические операции вложенного цикла, написанные как много и много курсоров. Победа над СУБД оптимизация. И бежит очень медленно.
простой SQL перезаписывает, чтобы заменить вложенные циклы курсора соединениями, и один плоский цикл курсора может заставить программы работать в 100-й раз. [Они думали, что я был богом оптимизации. Все, что я сделал, это заменил вложенные циклы соединениями. Все еще использовал курсоры.]
эта путаница часто приводит к обвинению курсоров. Однако проблема не в курсоре, а в неправильном использовании курсора.
в Размер Вопроса
для действительно эпических результирующих наборов (т. е. сброса таблицы в файл), курсоры имеют важное значение. Операции на основе наборов не могут материализовать действительно большие результирующие наборы в виде одной коллекции в памяти.
варианты
Я стараюсь использовать слой ORM как можно больше. Но это имеет две цели. Во-первых, курсоры управляются компонентом ORM. Во-вторых, SQL отделяется от приложения в файл конфигурации. Дело не в том, что курсоры плохие. Это кодирование всех тех, кто открывает, закрывает и получает не дополнительных программ.
курсоры заставляют людей чрезмерно применять процедурное мышление к среде на основе набора.
и медленно!!!
с SQLTeam:
обратите внимание, что курсоры являются Самый медленный способ доступа к данным внутри SQL Сервер. Следует использовать только тогда, когда вам действительно нужно получить доступ к одной строке время. Единственная причина я могу думать для этого нужно вызвать хранимую процедуру на каждом ряду. В курсор Статья производительности я обнаружил это курсорыболее тридцати раз медленнее, чем набор на основе альтернатив.
выше есть ответ, в котором говорится: "курсоры-это самый медленный способ доступа к данным внутри SQL Server... курсоры более чем в тридцать раз медленнее, чем набор на основе альтернатив."
Это утверждение может быть верным во многих случаях, но как общее утверждение, это проблематично. Например, я хорошо использовал курсоры в ситуациях, когда я хочу выполнить операцию обновления или удаления, влияющую на многие строки большой таблицы, которая получает постоянные производственные чтения. Работает хранимая процедура, которая делает эти обновления по одной строке за раз, оказывается быстрее, чем операции на основе набора, потому что операция на основе набора конфликтует с операцией чтения и в конечном итоге вызывает ужасные проблемы блокировки (и в крайних случаях может полностью убить производственную систему).
в отсутствие других действий с базой данных операции на основе набора универсально быстрее. В производственных системах это зависит.
курсоры, как правило, используются начинающими разработчиками SQL в местах, где операции на основе набора были бы лучше. В частности, когда люди изучают SQL после изучения традиционного языка программирования, менталитет "перебирать эти записи", как правило, приводит к тому, что люди используют курсоры неуместно.
большинство серьезных книг SQL включают главу, предписывающую использование курсоров; хорошо написанные дают понять, что курсоры имеют свое место, но не должны использоваться для набора на основе оперативный.
очевидно, что существуют ситуации, когда курсоры являются правильным выбором или, по крайней мере, правильным выбором.
оптимизатор часто не может использовать реляционную алгебру для преобразования задачи при использовании метода курсора. Часто курсор является отличным способом решения проблемы, но SQL является декларативным языком, и в базе данных есть много информации, от ограничений до статистики и индексов, которые означают, что оптимизатор имеет много вариантов для решения проблемы, тогда как курсор в значительной степени явно направляет решение.
в Oracle PL/SQL курсоры не будут приводить к блокировкам таблиц, и можно использовать массовый сбор/массовую выборку.
в Oracle 10 часто используется неявный курсор
for x in (select ....) loop --do something end loop;выбирает неявно 100 строк за раз. Также возможен явный массовый сбор / массовая выборка.
однако курсоры PL/SQL являются чем-то вроде последнего средства, используйте их, когда вы не можете решить проблему с SQL на основе набора.
еще одна причина распараллеливание, для базы данных легче распараллелить большие операторы на основе набора, чем строковый императивный код. Именно по этой причине функциональное программирование становится все более популярным (Haskell, F#, Lisp, C# LINQ, MapReduce ...), функциональное программирование упрощает распараллеливание. Число процессоров на компьютер растет, поэтому распараллеливание становится все более и более проблемой.
ответы выше не подчеркнули достаточно важность блокировки. Я не большой поклонник курсоров, потому что они часто приводят к блокировкам уровня таблицы.
В общем, потому что в реляционной базе данных производительность кода с использованием курсоров на порядок хуже, чем операции на основе наборов.
для чего это стоит, я прочитал, что" одно " место курсора будет выполнять его аналог на основе набора в текущем итоге. Над небольшой таблицей скорость суммирования строк по столбцам по порядку благоприятствует операции на основе набора, но по мере увеличения размера таблицы курсор станет быстрее, потому что он может просто переносить текущее общее значение на следующий проход цикла. Сейчас здесь вы должны сделать, а это другой аргумент...
Я согласен со статьей на эту страницу:
http://weblogs.sqlteam.com/jeffs/archive/2008/06/05/sql-server-cursor-removal.aspx
за пределами проблем с производительностью (не), я думаю, что самый большой недостаток курсоров-это их болезненная отладка. Особенно по сравнению с кодом в большинстве клиентских приложений, где отладка, как правило, сравнительно легко и языковые функции, как правило, гораздо проще. Фактически, я утверждаю, что почти все, что вы делаете в SQL с курсором, вероятно, должно происходить в клиентском приложении в первую очередь.
можете ли вы опубликовать этот пример курсора или ссылку на вопрос? Вероятно, есть даже лучший способ, чем рекурсивный CTE.
в дополнение к другим комментариям, курсоры при неправильном использовании (что часто) вызывают ненужные блокировки страниц/строк.
вы могли бы, вероятно, завершить свой вопрос после второго абзаца, а не называть людей "безумными" просто потому, что у них другая точка зрения, чем у вас, и в противном случае пытаться высмеять профессионалов, у которых может быть очень хорошая причина чувствовать себя так, как они это делают.
Что касается вашего вопроса, хотя, конечно, есть ситуации, когда курсор может быть вызван, по моему опыту разработчики решают, что курсор "должен" использоваться гораздо чаще, чем на самом деле случай. На мой взгляд, вероятность того, что кто-то ошибается на стороне слишком большого использования курсоров, а не использует их, когда они должны быть намного выше.
в основном 2 блоков кода, которые делают то же самое. может быть, это немного странный пример, но он доказывает это. SQL Server 2005:
SELECT * INTO #temp FROM master..spt_values DECLARE @startTime DATETIME BEGIN TRAN SELECT @startTime = GETDATE() UPDATE #temp SET number = 0 select DATEDIFF(ms, @startTime, GETDATE()) ROLLBACK BEGIN TRAN DECLARE @name VARCHAR DECLARE tempCursor CURSOR FOR SELECT name FROM #temp OPEN tempCursor FETCH NEXT FROM tempCursor INTO @name SELECT @startTime = GETDATE() WHILE @@FETCH_STATUS = 0 BEGIN UPDATE #temp SET number = 0 WHERE NAME = @name FETCH NEXT FROM tempCursor INTO @name END select DATEDIFF(ms, @startTime, GETDATE()) CLOSE tempCursor DEALLOCATE tempCursor ROLLBACK DROP TABLE #tempодно обновление занимает 156 МС, в то время как курсор занимает 2016 МС.
Comments