Вопрос

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

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

Спасибо

Это было полезно?

Решение

«Лучшая практика» избегания курсоров в SQL Server датируется SQL Server 2000 и более ранним версиями. Переписывание двигателя в SQL 2005 решило большинство вопросов, связанных с проблемами курсоров, особенно с внедрением опции Fast Forward. Курсоры не обязательно хуже, чем на основе установки и широко и успешно используются в Oracle PL/SQL (Loop).

«Общепринятый», на который вы ссылаетесь был Действительно, но теперь устарел и неверно - поступайте в предположение, что первые курсоры вперед ведут себя как рекламируемые и выступающие. Сделайте некоторые тесты и исследования, основывая свои выводы на SQL2005 и позже

Другие советы

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

Вот несколько ссылок, которые будут только вершиной айсберга, только если вы изучите эту проблему:

http://www.code-magazine.com/article.aspx?quickid=060113

http://dataeducation.com/re-inventing-the-recurisive-cte/

Этот ответ надеется объединить ответы, приведенные до настоящего времени.

1) Если это вообще, используется логика на основе наборов для ваших запросов, то есть попробуйте использовать просто SELECT, INSERT, UPDATE или DELETE с соответствующим FROM Положения или вложенные запросы - они почти всегда будут быстрее.

2) Если вышеперечисленное невозможно, то в SQL Server 2005+ FAST FORWARD Курсоры эффективны и работают хорошо и должны использоваться в предпочтениях, в то время как петли.

«Если вы хотите еще быстрее курсор, чем быстро вперед, используйте статический курсор. Они быстрее, чем быстро вперед. Не очень быстрее, но может изменить ситуацию».

Не так быстро! Согласно Microsoft: «Как правило, когда эти преобразования происходили, тип курсора разлагается до« более дорогого »типа курсора. Как правило, (быстрый) курсор, только перспективный, является наиболее эффективным, с последующим динамическим, Keyset и, наконец, статический как правило, наименее исполнительный ».

от: http://blogs.msdn.com/b/mssqlisv/archive/2006/06/23/644493.aspx

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

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

Попробуйте использовать его на проблеме Хэллоуина, чтобы увидеть, что произойдет !!!

IF OBJECT_ID('Funcionarios') IS NOT NULL
DROP TABLE Funcionarios
GO

CREATE TABLE Funcionarios(ID          Int IDENTITY(1,1) PRIMARY KEY,
                          ContactName Char(7000),
                          Salario     Numeric(18,2));
GO

INSERT INTO Funcionarios(ContactName, Salario) VALUES('Fabiano', 1900)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Luciano',2050)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Gilberto', 2070)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Ivan', 2090)
GO

CREATE NONCLUSTERED INDEX ix_Salario ON Funcionarios(Salario)
GO

-- Halloween problem, will update all rows until then reach 3000 !!!
UPDATE Funcionarios SET Salario = Salario * 1.1
  FROM Funcionarios WITH(index=ix_Salario)
 WHERE Salario < 3000
GO

-- Simulate here with all different CURSOR declarations
-- DYNAMIC update the rows until all of then reach 3000
-- FAST_FORWARD update the rows until all of then reach 3000
-- STATIC update the rows only one time. 

BEGIN TRAN
DECLARE @ID INT
DECLARE TMP_Cursor CURSOR DYNAMIC 
--DECLARE TMP_Cursor CURSOR FAST_FORWARD
--DECLARE TMP_Cursor CURSOR STATIC READ_ONLY FORWARD_ONLY
    FOR SELECT ID 
          FROM Funcionarios WITH(index=ix_Salario)
         WHERE Salario < 3000

OPEN TMP_Cursor

FETCH NEXT FROM TMP_Cursor INTO @ID

WHILE @@FETCH_STATUS = 0
BEGIN
  SELECT * FROM Funcionarios WITH(index=ix_Salario)

  UPDATE Funcionarios SET Salario = Salario * 1.1 
   WHERE ID = @ID

  FETCH NEXT FROM TMP_Cursor INTO @ID
END

CLOSE TMP_Cursor
DEALLOCATE TMP_Cursor

SELECT * FROM Funcionarios

ROLLBACK TRAN
GO

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

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

Эта статья Подчеркивает, что средний курсор работает в 50 раз быстрее, чем цикл.

Некоторые альтернативы использованию курсора:

В то время как петли Temp Tablolar Tables, связанные с высказываниями, которые часто связаны с множественными вопросами, операции курсора также могут быть достигнуты с помощью методов, не относящихся к Cursor.

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

Некоторые свойства курсора, которые влияют на производительность, включают:

Forward_only: поддерживает пересылку только курсор от первой строки до конца с Fetch Next. Если не установлено как Keyset или Static, пункт SELECT переоценивается при вызове каждого выпуска.

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

Keyset: Скскрятные ряды помещаются в таблицу под TempdB, а изменения в некологах отражаются при вызове выпуска. Однако новые записи, добавленные в таблицу, не отражены. С курсором Keyset, оператор SELECT больше не оценивается.

Динамика: все изменения в таблице отражены в керсуре. Курсор переоценивается при вызове каждой выборки. Он использует много ресурсов и отрицательно влияет на производительность.

FAST_FORWARD: Курсор находится в одностороннем движении, например, вперед, но определяет курсор как только для чтения. Forward_only - это увеличение производительности, и курсор не переоценивает каждый выбор. Это дает наилучшую производительность, если он подходит для программирования.

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

ПРИМЕЧАНИЕ. Если Cursore не указан, по умолчанию является вперед.

Чтобы ответить на исходные вопросы Майлы ...

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

Чтобы добавить к тому, что Эрик З. Борода опубликовал в этой теме, и чтобы еще больше ответить на вопрос ...

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

Да. За очень небольшим количеством исключений требуется меньше времени и меньше кода, чтобы написать правильный код на основе наборов, чтобы сделать то же самое, что и большинство курсоров, и имеет дополнительное преимущество в использовании гораздо меньшего количества ресурсов и обычно работает намного быстрее, чем курсор или во время цикла. Вообще говоря, и, за исключением определенных административных задач, их действительно следует избегать в пользу правильно написанного кода на основе наборов. Есть, конечно, исключения из каждого «правила», но в случае курсоров, в то время как петли и другие формы RBAR, большинство людей могут считать исключения, с одной стороны, не используя все пальцы. ;-)

Есть также понятие «Скрытый rbar». Это код, который выглядит на основе сбора, но на самом деле не. Этот тип кода «на основе наборов» является причиной того, что некоторые люди приняли методы RBAR и говорят, что они «хорошо». Например, решение общей задачи с использованием агрегированного (сумма) коррелированного подрегистрирования с неравенством в ней для создания общего числа, не установленная в моей книге. Вместо этого это RBAR на стероидах, потому что для каждой рассчитанной строки он должен неоднократно «касаться» многих других рядов со скоростью n*(n+1)/2. Это известно как «треугольное соединение» и, по крайней мере, наполовину так же плохо, как и полное декартовое соединение (Cross Join или «квадратное соединение»).

Хотя MS сделал некоторые улучшения в том, как курсоры работают со времен SQL Server 2005, термин «быстрый курсор» по-прежнему остается оксюмороном по сравнению с правильно написанным набором кода. Это также верно даже в Oracle. Я работал с Oracle в течение коротких 3 лет, но моя работа заключалась в улучшении производительности в существующем коде. Большинство действительно существенных улучшений были реализованы, когда я преобразовал курсоры в код на основе на основе на основе на основе на основе на основе на основе на основе на основе. Многие рабочие места, которые ранее занимали от 4 до 8 часов, были сокращены до минут и иногда, секунды.

Если вы хотите еще быстрее курсор, чем быстро вперед, используйте статический курсор. Они быстрее, чем быстро вперед. Не очень быстрее, но может изменить ситуацию.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top