Что различные пути состоят в том, чтобы заменить курсор?

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

Чтобы быть действительно придирчивым, я бы постарался сохранить интерфейс класса настолько чистым, насколько это возможно, поэтому, если строки имени файла не должны представлять интереса для «внешнего» мира. Я бы скрыл их внутри только в .cpp-файле. И в этом случае я не думаю, что буду беспокоиться о пространстве имен, а просто сохраню «статичность» (т. Е. Внутреннюю по отношению к .cpp-файлу).

5
задан tshepang 15 April 2014 в 17:05
поделиться

4 ответа

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

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

INSERT INTO YourTable
        (col1, col2, col3, col4)
    SELECT
        cola, colb+Colz, colc, @X
        FROM ....
            LEFT OUTER JOIN ...
        WHERE...

Глядя на цикл, посмотрите, что он внутри него делал. Если он просто вставляет / удаляет / обновляет, перезапишите, чтобы использовать отдельные команды. Если есть IF, посмотрите, могут ли они быть операторами CASE или условиями WHERE при вставке / удалении / обновлении. Если это так, удалите цикл и используйте команды set.

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

если вам нужно зациклить, сделайте что-то вроде этого над набором:

--this looks up each row for every iteration
DECLARE @msg VARCHAR(250)
DECLARE @hostname sysname

--first select of currsor free loop
SELECT @hostname= min(RTRIM(hostname))
    FROM  master.dbo.sysprocesses (NOLOCK)
    WHERE  hostname <> ''

WHILE @hostname is not null
BEGIN
    set @msg='exec master.dbo.xp_cmdshell "net send ' 
        + RTRIM(@hostname) + ' '
        + 'testing  "'
    print @msg
    --EXEC (@msg)

    --next select of cursor free loop
    SELECT @hostname= min(RTRIM(hostname))
        FROM master.dbo.sysprocesses (NOLOCK)
        WHERE  hostname <> ''
        and hostname > @hostname
END

если у вас есть разумный набор элементов (не 100 000), чтобы перебрать вас можно сделать это:

--this will capture each Key to loop over
DECLARE @msg VARCHAR(250)
DECLARE @From   int
DECLARE @To     int
CREATE TABLE #Rows
(
     RowID     int not null primary key identity(1,1)
    ,hostname  varchar(100)
)

INSERT INTO #Rows
SELECT DISTINCT hostname
    FROM  master.dbo.sysprocesses (NOLOCK)
    WHERE  hostname <> ''
SELECT @From=0,@To=@@ROWCOUNT

WHILE @From<@To
BEGIN
    SET @From=@From+1

    SELECT @msg='exec master.dbo.xp_cmdshell "net send ' 
        + RTRIM(hostname) + ' '
        + 'testing  "'
        FROM #Rows WHERE RowID=@From
    print @msg
    --EXEC (@msg)
END
7
ответ дан 18 December 2019 в 14:50
поделиться

Я заменил некоторые курсоры на циклы WHILE.

DECLARE @SomeTable TABLE
(
     ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
     SomeNumber int,
     SomeText varchar
)

DECLARE @theCount int
DECLARE @theMax int

DECLARE @theNumber int
DECLARE @theText varchar

INSERT INTO @SomeTable (SomeNumber, SomeText)
SELECT Number, Text
FROM PrimaryTable

SET @theCount = 1
SELECT @theMax = COUNT(ID) FROM @SomeTable

WHILE (@theCount <= @theMax)
BEGIN

     SET @theNumber = 0
     SET @theText = ''

     SELECT @theNumber = IsNull(Number, 0), @theText = IsNull(Text, 'nothing')
     FROM @SomeTable
     WHERE ID = @theCount

     -- Do something.
     PRINT 'This is ' + @theText + ' from record ' + CAST(@theNumber AS varchar) + '.'

     SET @theCount = @theCount + 1

END

PRINT 'Done'
4
ответ дан 18 December 2019 в 14:50
поделиться

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

Первоначально я это делал. это с помощью курсора, и с функциональной точки зрения это соответствовало бизнес-требованиям. С технической точки зрения это оказалось препятствием, потому что по мере увеличения объема данных код занимал экспоненциально больше времени. Решением было заменить курсор на коррелированный подзапрос, который отвечал функциональным требованиям и устранил любые проблемы с производительностью.

Надеюсь, это поможет,

Билл

0
ответ дан 18 December 2019 в 14:50
поделиться

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

Чаще всего подойдет SELECT с правильными параметрами - или, может быть, вы имеете дело с оператором UPDATE.

Суть в том, что вам нужно начать думать в виде операций над наборами и сообщать своей СУБД, что вы хотите сделано - не как сделать это шаг за шагом.

Трудно дать единственный, "правильный" ответ на этот вопрос ... вам почти придется показать это на конкретном примере.

Marc

2
ответ дан 18 December 2019 в 14:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: