Курсор SQL-сервера медленная производительность - PullRequest
4 голосов
/ 15 февраля 2012

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

Edit: Sprocs, который я буду вызывать для каждого символа, по большей части будут операциями вставки для вычисления значений, зависящих от символов, таких как скользящее среднее за 5 дней, среднесуточный объем, ATR (средний истинный диапазон). Большинство из этих значений будут рассчитываться на основе данных из таблицы ежедневных цен и объемов ... Я хотел бы упростить поиск значений данных, которые в противном случае были бы получены излишне ... например, я хотел бы получить для каждого Обозначьте ежедневные данные о ценах и объемах в табличной переменной ... эта временная таблица затем будет передана в хранимую процедуру, которая вызывает каждую из агрегированных функций, которые я только что упомянул. Надеюсь, что это имеет смысл ...

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

ALTER PROCEDURE dbo.sprocSymbolDependentAggsDriver2

    AS

    DECLARE @symbol nchar(10)
    DECLARE symbolCursor CURSOR
    STATIC FOR
    SELECT Symbol FROM tblSymbolsMain ORDER BY Symbol

    OPEN symbolCursor
    FETCH NEXT FROM symbolCursor INTO @symbol
    WHILE @@FETCH_STATUS = 0
        SET @symbol = @symbol + ': Test.'
        FETCH NEXT FROM symbolCursor INTO @symbol

    CLOSE symbolCursor
    DEALLOCATE symbolCursor

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

Ответы [ 4 ]

5 голосов
/ 15 февраля 2012

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

Курсоры редко нужны.

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

-- Create a temporary table...
CREATE TABLE #Symbols (
 RowID int IDENTITY(1, 1), 
 Symbol(nvarchar(max))
)
DECLARE @NumberRecords int, @RowCount int
DECLARE @Symbol nvarchar(max)

-- Get your data that you want to loop over
INSERT INTO #Symbols (Symbol)
SELECT Symbol
FROM tblSymbolsMain 
ORDER BY Symbol

-- Get the number of records you just grabbed
SET @NumberRecords = @@ROWCOUNT
SET @RowCount = 1


-- Just do a WHILE loop.  No cursor necessary.
WHILE @RowCount <= @NumberRecords
BEGIN
 SELECT @Symbol = Symbol
 FROM #Symbols
 WHERE RowID = @RowCount

 EXEC <myProc1> @Symbol
 EXEC <myProc2> @Symbol
 EXEC <myProc3> @Symbol

 SET @RowCount = @RowCount + 1
END


DROP TABLE #Symbols
2 голосов
/ 15 февраля 2012

вам нужен начальный конец:

WHILE @@FETCH_STATUS = 0 BEGIN
    SET @symbol = @symbol + ': Test.'
    FETCH NEXT FROM symbolCursor INTO @symbol
END

и попробуйте DECLARE symbolCursor CURSOR LOCAL READ_ONLY FORWARD_ONLY вместо STATIC для повышения производительности.

2 голосов
/ 15 февраля 2012

Вам не нужен весь этот явный джаз курсора для построения строки. Вот, вероятно, более эффективный способ сделать это:

DECLARE @symbol NVARCHAR(MAX) = N'';

SELECT @symbol += ': Test.'
    FROM dbo.tblSymbolsMain 
    ORDER BY Symbol;

Хотя я подозреваю, что вы действительно хотели увидеть названия символа, например,

DECLARE @symbol NVARCHAR(MAX) = N'';

SELECT @symbol += N':' + Symbol
    FROM dbo.tblSymbolsMain 
    ORDER BY Symbol;

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

DECLARE symbolCursor CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
...

Также мне кажется, что NCHAR (10) недостаточно для хранения данных, которые вы пытаетесь вставить в него, если только у вас нет только одной строки (именно поэтому я выбрал NVARCHAR(MAX) выше).

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

0 голосов
/ 27 сентября 2015

После прочтения всех предложений, я закончил делать какой-то старый трюк, и он творил чудеса!

У меня был этот курсор, который работал почти 3 минуты, в то время как включающий запрос был мгновенным. У меня есть другие базы данных с более сложными курсорами, которые занимали всего 1 секунду или меньше, поэтому я исключил глобальную проблему использования курсоров. Мое решение:

  1. Отсоедините базу данных, о которой идет речь, но убедитесь, что вы отметили опцию Обновить статистику.
  2. Присоединить базу данных и проверить производительность

Похоже, что это помогает оптимизировать все параметры производительности без подробных усилий. Я использую SQL Express 2008 R2.

Хотелось бы узнать ваш опыт.

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