Быстрые прямые курсоры SQL Server - PullRequest
7 голосов
/ 31 августа 2008

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

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

Спасибо

Ответы [ 9 ]

17 голосов
/ 02 сентября 2008

Несмотря на то, что курсор ускоренной перемотки вперед имеет некоторые оптимизации в Sql Server 2005, не верно, что они где-то близки к основанному на множестве запросу с точки зрения производительности. Очень мало ситуаций, когда логику курсора нельзя заменить запросом на основе набора. Курсоры всегда будут медленнее по своей природе, отчасти из-за того, что вам нужно продолжать прерывать выполнение, чтобы заполнить ваши локальные переменные.

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

http://www.code -magazine.com / Article.aspx? Quickid = 060113

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

2 голосов
/ 08 декабря 2014

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

Просто помните, что FAST_FORWARD ДИНАМИЧНЫЙ ... FORWARD_ONLY, который вы можете использовать с курсором STATIC.

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

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
2 голосов
/ 13 июля 2010

"Если вам нужен еще более быстрый курсор, чем FAST FORWARD, используйте курсор STATIC. Они быстрее, чем FAST FORWARD. Не очень быстро, но могут иметь значение."

Не так быстро! По словам Microsoft: «Обычно, когда происходят эти преобразования, тип курсора ухудшается до« более дорогого »типа курсора. Как правило, (FAST) курсор FORWARD-ONLY является наиболее быстродействующим, за ним следуют DYNAMIC, KEYSET и, наконец, STATIC, который обычно является наименьшим производительный ".

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

1 голос
/ 12 июля 2018

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

WHILE петли Temp Tablolar Производные таблицы Связанные подзапросы CASE заявления Многократные допросы Зачастую операции с курсорами также могут быть выполнены с помощью некурсорных методов.

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

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

FORWARD_ONLY: Поддерживает пересылку только курсора от первого ряда до конца с помощью FETCH NEXT. Если не задано KEYSET или STATIC, предложение SELECT переоценивается при вызове каждой выборки.

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

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

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

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

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

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

1 голос
/ 20 января 2009

Этот ответ надеется объединить ответы, данные на сегодняшний день.

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

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

1 голос
/ 01 сентября 2008

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

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

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

0 голосов
/ 31 декабря 2012

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

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

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

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

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

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

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

0 голосов
/ 18 сентября 2008

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

0 голосов
/ 02 сентября 2008

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

«Общепринятый», который вы ссылаетесь на , был действительным, но теперь устарел и неверен - исходя из того, что курсоры перемотки вперед ведут себя так, как объявлено и работает. Проведите несколько тестов и исследований, основываясь на результатах SQL2005 и более поздних версий

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