SQL Server лучший способ перебирать миллионы строк

Я работаю с данными SAP Timesheet, поэтому есть миллионы строк. Я пытаюсь выбрать данные из таблицы SAP и вставить их в таблицу на MS SQL Server.

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

Итак, я успешно сделал это с помощью курсора (я не знаю лучшего), но с миллионами записей мне интересно, есть ли более быстрый способ, потому что я на 4-м дне работы моего курсора. Есть ли лучший способ, чем то, что у меня есть ниже:

BEGIN
    CREATE TABLE CATSDB 
        (
            [COUNTER] nvarchar(12),
            REFCOUNTER nvarchar(12),
            PERNR nvarchar(8),
            WORKDATE nvarchar(8),
            CATSHOURS decimal(7, 3),
            APDAT nvarchar(8),
            LAETM nvarchar(6),
            CATS_STATUS nvarchar(2),
            APPR_STATUS nvarchar(2)
        )   

    INSERT INTO CATSDB
            (
                [COUNTER],REFCOUNTER,PERNR,WORKDATE,CATSHOURS,APDAT,LAETM,CATS_STATUS,APPR_STATUS
            )
        VALUES
            ('000421692670',NULL,'00000071','20190114','6.00','20190204','174541','30','30'),
            ('000421692671',NULL,'00000071','20190114','3.00','20190204','174541','30','30'),
            ('000421692672',NULL,'00000071','20190115','6.00','00000000','000000','60','20'),
            ('000421692673',NULL,'00000071','20190115','3.00','00000000','000000','60','20'),
            ('000421692712','000421692672','00000071','20190115','0.00','20190115','111007','30','30'),
            ('000421692713','000421692673','00000071','20190115','0.00','20190115','111007','30','30'),
            ('000429718015',NULL,'00000072','20190313','7.00','00000000','000000','60','20'),
            ('000429718016',NULL,'00000072','20190313','1.50','20190315','164659','30','30'),
            ('000429718017',NULL,'00000072','20190313','1.00','20190315','164659','30','30'),
            ('000430154143',NULL,'00000072','20190313','2.00','00000000','000000','60','20'),
            ('000430154142','000429718015','00000072','20190313','5.00','00000000','000000','60','20'),
            ('000430154928','000430154142','00000072','20190313','4.50','20190315','164659','30','30'),
            ('000430154929','000430154143','00000072','20190313','2.50','20190315','164659','30','30'),
            ('000429774620',NULL,'00000152','20190314','1.00','00000000','000000','60','20'),
            ('000429774619',NULL,'00000152','20190314','1.00','00000000','000000','60','20'),
            ('000429802106','000429774620','00000152','20190314','2.00','00000000','000000','60','20'),
            ('000429802105','000429774619','00000152','20190314','3.00','00000000','000000','60','20'),
            ('000429840242','000429802106','00000152','20190314','4.00','20190315','143857','30','30'),
            ('000429840241','000429802105','00000152','20190314','5.00','20190315','143857','30','30')

    CREATE TABLE [TBL_COUNTER]
        (
            [COUNTER] [varchar](12) NOT NULL,
            [REFCOUNTER] [varchar](12) NULL
        )   

    CREATE TABLE TEMP
        (
            [COUNTER] [nvarchar](12) NOT NULL,
            [REFCOUNTER] [nvarchar](12) NULL,
            [PERNR] [nvarchar](8) NULL,
            [WORKDATE] [nvarchar](8) NULL,
            [CATSHOURS] [decimal](7, 3) NULL,
            [APDAT] [nvarchar](8) NULL,
            [LAETM] [nvarchar](6) NULL,
            [CATS_STATUS] [nvarchar](2) NULL,
            [APPR_STATUS] [nvarchar](2) NULL
        )       
END

BEGIN
    DECLARE     @COUNTER nvarchar(12),  
                @REFCOUNTER nvarchar(12),   
                @PERNR nvarchar(8), 
                @WORKDATE nvarchar(8),  
                @CATSHOURS decimal(7, 3),
                @APDAT nvarchar(8),
                @LAETM nvarchar(6),
                @CATS_STATUS nvarchar(2),
                @APPR_STATUS nvarchar(2)

    DECLARE @orig_counter nvarchar(12)
END

BEGIN
    DECLARE curs CURSOR FOR
        SELECT 
                [COUNTER],
                REFCOUNTER,
                PERNR,
                WORKDATE,
                CATSHOURS,
                APDAT,
                LAETM,
                CATS_STATUS,
                APPR_STATUS
        FROM 
                CATSDB
END

BEGIN
    OPEN curs
END

BEGIN
    FETCH NEXT FROM curs INTO
        @COUNTER,
        @REFCOUNTER,
        @PERNR,
        @WORKDATE,
        @CATSHOURS,
        @APDAT,
        @LAETM,
        @CATS_STATUS,
        @APPR_STATUS
END

BEGIN
    WHILE @@FETCH_STATUS = 0
        BEGIN
            BEGIN
                IF NOT EXISTS (SELECT * FROM TBL_COUNTER WHERE [COUNTER] = @COUNTER)
                    BEGIN
                        INSERT INTO TBL_COUNTER
                                ([COUNTER]
                                ,REFCOUNTER)
                            VALUES
                                (@COUNTER
                                ,@REFCOUNTER)
                    END
            END
            BEGIN
                IF NOT EXISTS (SELECT * FROM TEMP WHERE [COUNTER] = @COUNTER)
                    BEGIN
                            --If REFCOUNTER is populated, get the original COUNTER value, then update that row with the new values. Otherwise insert new record
                            IF @REFCOUNTER <> '' AND @REFCOUNTER IS NOT NULL
                                BEGIN
                                    BEGIN
                                        WITH n([COUNTER], REFCOUNTER) AS 
                                            (
                                                SELECT 
                                                        cnt.[COUNTER], 
                                                        cnt.REFCOUNTER 
                                                FROM 
                                                        TBL_COUNTER cnt
                                                WHERE 
                                                        cnt.[COUNTER] = @REFCOUNTER
                                            UNION ALL
                                                SELECT 
                                                        nplus1.[COUNTER], 
                                                        nplus1.REFCOUNTER 
                                                FROM 
                                                        TBL_COUNTER as nplus1, 
                                                        n
                                                WHERE 
                                                        n.[COUNTER] = nplus1.REFCOUNTER
                                            )
                                        SELECT @orig_counter = [COUNTER] FROM n WHERE REFCOUNTER = '' OR REFCOUNTER IS NULL
                                    END
                                    BEGIN
                                        UPDATE TEMP
                                           SET 
                                               [REFCOUNTER] = @REFCOUNTER
                                              ,[PERNR] = @PERNR 
                                              ,[WORKDATE] = @WORKDATE                                               
                                              ,[CATSHOURS] = @CATSHOURS                                                                                    
                                              ,[APDAT] = @APDAT                                        
                                              ,[LAETM] = @LAETM
                                              ,[CATS_STATUS] = @CATS_STATUS
                                              ,[APPR_STATUS] = @APPR_STATUS                                        
                                            WHERE [COUNTER] = @orig_counter
                                    END
                                END
                            ELSE
                                BEGIN
                                    INSERT INTO TEMP
                                               ([COUNTER]
                                               ,[REFCOUNTER]                                               
                                               ,[PERNR]                                               
                                               ,[WORKDATE]                                               
                                               ,[CATSHOURS]                                             
                                               ,[APDAT]                                              
                                               ,[LAETM]
                                               ,[CATS_STATUS]                                               
                                               ,[APPR_STATUS])                                              
                                         VALUES
                                               (@COUNTER
                                               ,@REFCOUNTER                                              
                                               ,@PERNR                                               
                                               ,@WORKDATE                                             
                                               ,@CATSHOURS                                               
                                               ,@APDAT                                               
                                               ,@LAETM                                               
                                               ,@CATS_STATUS                                               
                                               ,@APPR_STATUS)                                               
                                END
                    END

            FETCH NEXT FROM curs INTO
                @COUNTER,
                @REFCOUNTER,
                @PERNR,
                @WORKDATE,
                @CATSHOURS,
                @APDAT,
                @LAETM,
                @CATS_STATUS,
                @APPR_STATUS
        END
    END
END

BEGIN
    CLOSE curs
    DEALLOCATE curs
END

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

+--------------+--------------+----------+----------+-----------+----------+--------+-------------+-------------+
|   COUNTER    |  REFCOUNTER  |  PERNR   | WORKDATE | CATSHOURS |  APDAT   | LAETM  | CATS_STATUS | APPR_STATUS |
+--------------+--------------+----------+----------+-----------+----------+--------+-------------+-------------+
| 000421692670 | NULL         | 00000071 | 20190114 |      6.00 | 20190204 | 174541 |          30 |          30 |
| 000421692671 | NULL         | 00000071 | 20190114 |      3.00 | 20190204 | 174541 |          30 |          30 |
| 000421692672 | 000421692672 | 00000071 | 20190115 |      0.00 | 20190115 | 111007 |          30 |          30 |
| 000421692673 | 000421692673 | 00000071 | 20190115 |      0.00 | 20190115 | 111007 |          30 |          30 |
| 000429718015 | 000430154142 | 00000072 | 20190313 |      4.50 | 20190315 | 164659 |          30 |          30 |
| 000429718016 | NULL         | 00000072 | 20190313 |      1.50 | 20190315 | 164659 |          30 |          30 |
| 000429718017 | NULL         | 00000072 | 20190313 |       1.0 | 20190315 | 164659 |          30 |          30 |
| 000430154143 | 000430154143 | 00000072 | 20190313 |      2.50 | 20190315 | 164659 |          30 |          30 |
| 000429774620 | 000429774620 | 00000152 | 20190314 |      2.00 | 00000000 | 000000 |          60 |          20 |
| 000429774619 | 000429802105 | 00000152 | 20190314 |      5.00 | 20190315 | 143857 |          30 |          30 |
+--------------+--------------+----------+----------+-----------+----------+--------+-------------+-------------+

Мне нужно добавить к этому. Итак, здесь есть две фазы. На первом этапе я извлеку все данные за 2019 год для первоначальной загрузки моей таблицы. Затем еженедельно я буду извлекать данные из исходного источника для новых записей и измененных записей с момента последнего запуска. Так что у меня не будет полной цепочки каждую неделю. Должен быть способ вернуться к исходному значению счетчика без полного набора данных, поэтому у меня была таблица счетчика. Прошу прощения за то, что не выразился более ясно. Я завален работой и не смог сосредоточиться на этом столько, сколько планировал. Я пробую все эти разные техники.


person dk96m    schedule 21.08.2019    source источник
comment
Курсор будет буквально худшим способом сделать это. Возможно, вы захотите делать это партиями, но курсор означает, что вы собираетесь делать этот ряд за мучительным рядом (RBAR). Возможно, вы могли бы предоставить нам некоторые образцы данных и ожидаемые результаты для вашего SQL здесь?   -  person Larnu    schedule 21.08.2019
comment
Глядя на то, что у вас есть, возможно, вам нужен MERGE?   -  person Larnu    schedule 21.08.2019
comment
Я бы переписал это на 2 утверждения. Один из них обновляет все строки из уже существующего запроса, а другой вставляет все строки из запроса, которого у вас еще нет. Оба должны запускаться отдельно друг от друга. Таким образом, вам не нужен курсор, который убивает вашу производительность.   -  person GuidoG    schedule 21.08.2019
comment
Позвольте мне собрать некоторые образцы данных и вернуться к вам. Я знаю, что это наихудший способ сделать это. Я не эксперт, поэтому это то, что я придумал, но теперь, когда оно работает уже 4 дня, да, не самое лучшее. Проблема в том, что исходная запись может иметь более одного изменения, поэтому существует несколько записей с несколькими счетчиками ссылок, поэтому у меня есть таблица TCATMSTR_COUNTER, чтобы вернуться, чтобы получить исходное значение счетчика.   -  person dk96m    schedule 21.08.2019
comment
Я не могу добавить запросы для создания таблиц и добавления данных, это слишком долго. Как мне предоставить эту информацию.   -  person dk96m    schedule 21.08.2019
comment
Может быть, вы можете ограничить данные, используя некоторую бизнес-логику SAP? Существуют правила, описывающие, когда счетчик обновляется. Если вы ограничитесь только утвержденными записями, у вас будет не так много изменений. Дополнительная информация: wiki.scn.sap.com/wiki/display/ERPHCM/   -  person Mikael G    schedule 21.08.2019
comment
@MikaelG, вы не можете этого сделать, потому что как вы найдете исходную запись для обновления? Я обновляю OP примерами. Если запись изменяется 5 раз в SAP, последняя утвержденная запись не знает, что такое исходная запись, если только вы не пройдете счетчик и счетчик ссылок, чтобы получить оригинал. Таким образом, если запись утверждена, а затем изменена несколько раз, вам потребуется получить все записи.   -  person dk96m    schedule 22.08.2019
comment
@dk96m, какую версию SQL Server вы используете? (SELECT @@Version) Пожалуйста, упростите ваш образец данных (единственные важные столбцы — это Counter и RefCounter, поэтому оставьте их и еще пару, например BELNR и CHARGE_HOLD. Никто не будет читать 20 столбцов. В то же время добавьте больше строк в образец data. Одного набора изменений недостаточно для проверки правильности работы запроса. Добавьте еще пару наборов/цепочек изменений.   -  person Vladimir Baranov    schedule 27.08.2019
comment
@dk96m Также уточните, пожалуйста, содержит ли последняя строка в цепочке изменений все необходимые данные? Я имею в виду, если мы найдем первую строку в цепочке с Counter=420202428 и последнюю строку с Counter=420331792, а затем скопируем все значения из всех столбцов из последней строки в первую строку, будет ли этого достаточно? Это также должно стать ясным, если вы предоставите хорошие упрощенные образцы данных.   -  person Vladimir Baranov    schedule 27.08.2019
comment
@ dk96m, также уточните, похоже, что Counter является первичным ключом, верно?   -  person Vladimir Baranov    schedule 27.08.2019
comment
проблема в начальной настройке? или для следующих обновлений?   -  person Tuckbros    schedule 28.08.2019
comment
@VladimirBaranov, Microsoft SQL Server 2016 (X64) для версии. Я буду работать над тем, чтобы сделать его еще проще. Это уже довольно просто, ИМО, но я понимаю, что такое столбцы. Я его уже сильно урезал.   -  person dk96m    schedule 30.08.2019
comment
@VladimirBaranov, вроде с последним и первым. Изменения не происходят одновременно. Я могу получить начальную запись, затем на следующей неделе два изменения, а затем еще одно на следующей неделе, поэтому вам нужно будет вернуться от последнего изменения к исходной записи всякий раз, когда поступают данные. Но по сути да, скопируйте все данные из последней строки в начальную строку, но с сохранением начального значения счетчика.   -  person dk96m    schedule 30.08.2019
comment
@VladimirBaranov да, я бы сказал, что counter и mandt являются первичными ключами   -  person dk96m    schedule 30.08.2019
comment
@VladimirBaranov хорошо, я обновляю ОП, чтобы было меньше столбцов и больше данных. Это помогает?   -  person dk96m    schedule 31.08.2019
comment
Можете ли вы заново объяснить вывод и расширить вознаграждение или, по крайней мере, переобъяснить вывод наилучшим образом. Спасибо.   -  person KumarHarsh    schedule 02.09.2019
comment
@KumarHarsh Я попытаюсь увеличить награду, если смогу понять, как это сделать. Что касается результата. Итак, для начальной загрузки я буду извлекать все данные за 2019 год из исходного источника. Я обработаю это. После этого я буду загружать только новые записи или измененные записи с момента последнего запуска, что будет еженедельно. Итак, приходит исходная запись, эта запись добавляется в мою таблицу. В исходную запись было внесено изменение, которое создает новую запись со счетчиком ссылок на предыдущий счетчик. Я хочу обновить исходную запись счетчика в моей таблице данными из новой записи.   -  person dk96m    schedule 03.09.2019
comment
@KumarHarsh сохраняет исходный счетчик записей. См. пример в ОП.   -  person dk96m    schedule 03.09.2019
comment
Извините за опоздание. Проверьте мой ответ. Я не понял, почему вы будете вставлять или удалять. Как будет выглядеть выбор * из CATSDB?   -  person KumarHarsh    schedule 11.09.2019


Ответы (6)


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

Он был создан для хранения исторической информации о серверах SQL в центральном расположении и выполняет следующие действия: вы должны включить/заменить структуры таблиц в соответствующих блоках скрипта.

  1. Создает temp таблицу
  2. Собирает информацию с нескольких серверов, используя OPENQUERY через Lined Servers (источник), и загружает в Temp таблицу.
  3. Создает индексы для Temp таблиц
  4. Загружает данные в центральную таблицу (назначение) с 3 сценариями (как указано в сценарии)

Примечание. Сценарий заменен в соответствии с вашим сценарием


BEGIN
    Create Table #SrcTemp
                    (   AENAM nvarchar(12),
                        AUTYP nvarchar(2),
                        AWART nvarchar(4),
                        BELNR nvarchar(10),
                        CATSHOURS decimal(7, 3),
                        CATSQUANTITY decimal(18, 3),
                        CHARGE_HOLD nvarchar(24),
                        [COUNTER] nvarchar(12),
                        ERNAM nvarchar(12),
                        ERSDA nvarchar(8),
                        ERSTM nvarchar(6),
                        HRCOSTASG nvarchar(1),
                        LAEDA nvarchar(8),
                        LSTAR nvarchar(6),
                        LTXA1 nvarchar(40),
                        MANDT nvarchar(3),
                        PERNR nvarchar(8),
                        RAPLZL nvarchar(8),
                        RAUFPL nvarchar(10),
                        REFCOUNTER nvarchar(12),
                        RNPLNR nvarchar(12),
                        SKOSTL nvarchar(10),
                        CATS_STATUS nvarchar(2),
                        SUPP3 nvarchar(10),
                        WORKDATE nvarchar(8),
                        ZZOH_ORDER nvarchar(24),
                        APDAT nvarchar(8),
                        APNAM nvarchar(12),
                        LAETM nvarchar(6),
                        APPR_STATUS nvarchar(2)
                    );

--    DECLARE @orig_counter nvarchar(12)
END
    UPDATE #SrcTemp SET REFCOUNTER = '0' WHERE  REFCOUNTER = '' or REFCOUNTER is null;
    CREATE Clustered Index CLU_SrvTemp on #SrcTemp ([COUNTER], REFCOUNTER);

BEGIN

        INSERT INTO #SrcTemp
        SELECT 
                AENAM,AUTYP,AWART,BELNR,CATSHOURS,CATSQUANTITY,CHARGE_HOLD,[COUNTER],ERNAM,ERSDA,ERSTM,HRCOSTASG,LAEDA,LSTAR,LTXA1,MANDT,
                PERNR,RAPLZL,RAUFPL,REFCOUNTER,RNPLNR,SKOSTL,CATS_STATUS,SUPP3,WORKDATE,ZZOH_ORDER,APDAT,APNAM,LAETM,APPR_STATUS
        FROM    
                CATSDB;
END

--BEGIN
--    OPEN curs
--END

-- Scope: UNCHANGED Records ==================================================================================================================================

    IF EXISTS 
        (select *
         from   (
                    SELECT ROW_NUMBER () OVER (PARTITION BY [COUNTER] ORDER BY COUNTER) AS RN
                    FROM    #SrcTemp
                    WHERE REFCOUNTER = '0'
                ) as t where t.RN > 1
         )
        BEGIN
            RAISERROR ('Primary key violation occurred in "UNCHANGED" records processing block', 16, 1) with NOWAIT;
        END
    ELSE 

    BEGIN
    -- When NON-CHANGED Records NOT Existed in SQL table -------------------------------------------
            BEGIN
                INSERT INTO TEMP  ([AENAM],[AUTYP],[AWART],[BELNR],[CATSHOURS],[CATSQUANTITY],[CHARGE_HOLD],[COUNTER],[ERNAM]
                                    ,[ERSDA],[ERSTM],[HRCOSTASG],[LAEDA],[LSTAR],[LTXA1],[MANDT],[PERNR],[RAPLZL],[RAUFPL]
                                    ,[REFCOUNTER],[RNPLNR],[SKOSTL],[CATS_STATUS],[SUPP3],[WORKDATE],[ZZOH_ORDER],[APDAT],[APNAM]
                                    ,[LAETM],[APPR_STATUS]
                                    )
                SELECT    s.[AENAM], s.[AUTYP], s.[AWART], s.[BELNR], s.[CATSHOURS], s.[CATSQUANTITY], s.[CHARGE_HOLD], s.[COUNTER], s.[ERNAM]
                        , s.[ERSDA], s.[ERSTM], s.[HRCOSTASG], s.[LAEDA], s.[LSTAR], s.[LTXA1], s.[MANDT], s.[PERNR], s.[RAPLZL], s.[RAUFPL]
                        , s.[REFCOUNTER], s.[RNPLNR], s.[SKOSTL], s.[CATS_STATUS], s.[SUPP3], s.[WORKDATE], s.[ZZOH_ORDER], s.[APDAT], s.[APNAM]
                        , s.[LAETM], s.[APPR_STATUS]
                FROM    #SrcTemp as S
                        LEFT JOIN
                            TEMP as D on s.COUNTER = d.COUNTER
                WHERE (S.REFCOUNTER = '0') and D.COUNTER is null ;
            END

        -- When NON-CHANGED Records Existed in SQL table -------------------------------------------
            BEGIN
                UPDATE S
                    SET [AENAM] = D.AENAM
                        ,[AUTYP] = D.AUTYP
                        ,[AWART] = D.AWART
                        ,[BELNR] = D.BELNR
                        ,[CATSHOURS] = D.CATSHOURS
                        ,[CATSQUANTITY] = D.CATSQUANTITY
                        ,[CHARGE_HOLD] = D.CHARGE_HOLD
                        ,[ERNAM] = D.ERNAM
                        ,[ERSDA] = D.ERSDA
                        ,[ERSTM] = D.ERSTM
                        ,[HRCOSTASG] = D.HRCOSTASG
                        ,[LAEDA] = D.LAEDA
                        ,[LSTAR] = D.LSTAR
                        ,[LTXA1] = D.LTXA1
                        ,[MANDT] = D.MANDT
                        ,[PERNR] = D.PERNR
                        ,[RAPLZL] = D.RAPLZL
                        ,[RAUFPL] = D.RAUFPL
                        ,[REFCOUNTER] = D.REFCOUNTER
                        ,[RNPLNR] = D.RNPLNR
                        ,[SKOSTL] = D.SKOSTL
                        ,[CATS_STATUS] = D.CATS_STATUS
                        ,[SUPP3] = D.SUPP3
                        ,[WORKDATE] = D.WORKDATE
                        ,[ZZOH_ORDER] = D.ZZOH_ORDER
                        ,[APDAT] = D.APDAT
                        ,[APNAM] = D.APNAM
                        ,[LAETM] = D.LAETM
                        ,[APPR_STATUS] = D.APPR_STATUS
                FROM    #SrcTemp as S
                        LEFT JOIN
                            TEMP as D on    (s.COUNTER = d.COUNTER and S.REFCOUNTER = D.REFCOUNTER)
                WHERE (S.REFCOUNTER = '0') and D.COUNTER is NOT null 
            END
    END

-- Scope: CHANGED Records ==================================================================================================================================

    IF EXISTS 
        (select *
         from   (
                    SELECT ROW_NUMBER () OVER (PARTITION BY [COUNTER], REFCOUNTER ORDER BY [COUNTER]) AS RN
                    FROM    #SrcTemp
                    WHERE not REFCOUNTER = '0' 
                ) as t where t.RN > 1
         )
        BEGIN
            RAISERROR ('Primary key violation occurred in "CHANGED" records processing block', 10, 1) with NOWAIT;
        END
    ELSE

    BEGIN
        -- When CHANGED Records NOT Existed in SQL table -------------------------------------------
            BEGIN
                INSERT INTO TEMP  ([AENAM],[AUTYP],[AWART],[BELNR],[CATSHOURS],[CATSQUANTITY],[CHARGE_HOLD],[COUNTER],[ERNAM]
                                    ,[ERSDA],[ERSTM],[HRCOSTASG],[LAEDA],[LSTAR],[LTXA1],[MANDT],[PERNR],[RAPLZL],[RAUFPL]
                                    ,[REFCOUNTER],[RNPLNR],[SKOSTL],[CATS_STATUS],[SUPP3],[WORKDATE],[ZZOH_ORDER],[APDAT],[APNAM]
                                    ,[LAETM],[APPR_STATUS]
                                    )
                SELECT    s.[AENAM], s.[AUTYP], s.[AWART], s.[BELNR], s.[CATSHOURS], s.[CATSQUANTITY], s.[CHARGE_HOLD], s.[COUNTER], s.[ERNAM]
                        , s.[ERSDA], s.[ERSTM], s.[HRCOSTASG], s.[LAEDA], s.[LSTAR], s.[LTXA1], s.[MANDT], s.[PERNR], s.[RAPLZL], s.[RAUFPL]
                        , s.[REFCOUNTER], s.[RNPLNR], s.[SKOSTL], s.[CATS_STATUS], s.[SUPP3], s.[WORKDATE], s.[ZZOH_ORDER], s.[APDAT], s.[APNAM]
                        , s.[LAETM], s.[APPR_STATUS]
                FROM    #SrcTemp as S
                        LEFT JOIN
                            TEMP as D on s.COUNTER = d.COUNTER and S.REFCOUNTER = D.REFCOUNTER
                WHERE (not S.REFCOUNTER = '0') and D.COUNTER is null 
            END

        -- When NON-CHANGED Records Existed in SQL table -------------------------------------------
            BEGIN
                UPDATE S
                    SET [AENAM] = D.AENAM
                        ,[AUTYP] = D.AUTYP
                        ,[AWART] = D.AWART
                        ,[BELNR] = D.BELNR
                        ,[CATSHOURS] = D.CATSHOURS
                        ,[CATSQUANTITY] = D.CATSQUANTITY
                        ,[CHARGE_HOLD] = D.CHARGE_HOLD
                        ,[ERNAM] = D.ERNAM
                        ,[ERSDA] = D.ERSDA
                        ,[ERSTM] = D.ERSTM
                        ,[HRCOSTASG] = D.HRCOSTASG
                        ,[LAEDA] = D.LAEDA
                        ,[LSTAR] = D.LSTAR
                        ,[LTXA1] = D.LTXA1
                        ,[MANDT] = D.MANDT
                        ,[PERNR] = D.PERNR
                        ,[RAPLZL] = D.RAPLZL
                        ,[RAUFPL] = D.RAUFPL
                        ,[REFCOUNTER] = D.REFCOUNTER
                        ,[RNPLNR] = D.RNPLNR
                        ,[SKOSTL] = D.SKOSTL
                        ,[CATS_STATUS] = D.CATS_STATUS
                        ,[SUPP3] = D.SUPP3
                        ,[WORKDATE] = D.WORKDATE
                        ,[ZZOH_ORDER] = D.ZZOH_ORDER
                        ,[APDAT] = D.APDAT
                        ,[APNAM] = D.APNAM
                        ,[LAETM] = D.LAETM
                        ,[APPR_STATUS] = D.APPR_STATUS
                FROM    #SrcTemp as S
                        LEFT JOIN
                        TEMP as D on s.COUNTER = d.COUNTER and S.REFCOUNTER = D.REFCOUNTER
                WHERE (not S.REFCOUNTER = '0' ) and D.COUNTER is NOT null 
            END
    END

Drop table #SrcTemp;
person Shekar Kola    schedule 21.08.2019
comment
Я не уверен, как перевести это в мои потребности. Я продолжаю смотреть на это. - person dk96m; 21.08.2019
comment
см. ОП, чтобы узнать, как он работает со счетчиком и счетчиком ссылок. Я мог бы обновлять исходную запись много раз, НО счетчик ссылок ссылается только на счетчик из предыдущего изменения (или исходную запись, если это первое изменение) - person dk96m; 21.08.2019
comment
Насколько я понимаю, таблица TCATMSTR_COUNTER выглядит как временная и обновляется во время выполнения скрипта. это помогло бы нам лучше понять сценарий, если бы вы могли предоставить некоторые примеры данных макета таблицы источника (SAP) и назначения (включая только необходимые столбцы) - person Shekar Kola; 21.08.2019
comment
Я обновил исходный пост, чтобы сократить его, создать таблицы, вставить данные и затем запустить курсор. Как я могу улучшить это по вашему предложению. - person dk96m; 22.08.2019
comment
Вы можете помочь мне? Он до сих пор работает, 9-й день. - person dk96m; 26.08.2019
comment
которые вы можете проверить с помощью select ROW_NUMBER () OVER (PARTITION BY COUNTER, REFCOUNTER ORDER BY COUNTER), * from CATSDB - person Shekar Kola; 26.08.2019
comment
Счетчик является ключевым столбцом, счетчик ссылок при заполнении ссылается на более раннюю строку. Таким образом, строка ссылок больше не является последней версией, а заменяется этой новой строкой. Так что это так. Каждая запись в таблице представляет одну запись в табеле учета рабочего времени для конкретной задачи. Итак, сегодня я ввожу 8 часов для задачи А. Но завтра я захожу и меняю ее на 9 часов. Что делает sap, так это устанавливает статус исходной записи как отмененный и создает новую запись с новой информацией, которая составляет 9 часов вместо 8. - person dk96m; 26.08.2019
comment
Для этой новой записи она имеет новое значение счетчика, а повторный счетчик имеет значение счетчика из исходной записи. Таким образом, он просто не обновляет исходную запись с 8 часов до 9 часов. Он создает совершенно новую запись со ссылкой на старую. Что я хочу сделать в своей таблице, так это сохранить исходное значение счетчика, но обновить все остальное, когда новые записи появятся в этой ссылке на более старую запись. Смотрите мой пример. Вы должны иметь возможность запустить его и посмотреть, что он делает. - person dk96m; 26.08.2019
comment
Давайте продолжим обсуждение в чате. - person Shekar Kola; 26.08.2019
comment
Это не сработало. Я попробовал это, и у него все еще есть исходная запись плюс записи обновлений. Записи обновления должны обновлять исходную запись, но с сохранением исходного счетчика. - person dk96m; 19.09.2019
comment
Чат закрыт? - person dk96m; 23.09.2019

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

Пример данных

Вот как ваши образцы данных должны выглядеть в вопросе. Только несколько соответствующих столбцов. Лучше включить несколько наборов/цепочек изменений, а не один. Имея только эти образцы данных, вам будет сложнее проверить правильность представленных решений.

+-----------+---------------------+-----------+------------+
|   BELNR   |     CHARGE_HOLD     |  COUNTER  | REFCOUNTER |
+-----------+---------------------+-----------+------------+
| 417548605 | T4-GS023ABC2 0150#* | 420202428 | NULL       |
| 417549506 | T4-GS023-ABC2       | 420203329 | 420202428  |
| 417553156 | JGS023001    0010#* | 420206979 | 420203329  |
| 417557221 | T4-GS023-ABC2       | 420211044 | 420206979  |
| 417581675 | JGS023001    0010#* | 420235498 | 420211044  |
| 417677969 | JGS023001    0010#* | 420331792 | 420235498  |
+-----------+---------------------+-----------+------------+

Основная рекурсивная часть запроса

WITH
CTE
AS
(
    SELECT
        1 AS Lvl,
        CATSDB.BELNR AS OriginalBELNR,
        CATSDB.CHARGE_HOLD AS OriginalCHARGE_HOLD,
        CATSDB.[COUNTER] AS OriginalCOUNTER,
        CATSDB.REFCOUNTER AS OrginalREFCOUNTER,
        CATSDB.BELNR AS NewBELNR,
        CATSDB.CHARGE_HOLD AS NewCHARGE_HOLD,
        CATSDB.[COUNTER] AS NewCOUNTER,
        CATSDB.REFCOUNTER AS NewREFCOUNTER
    FROM
        CATSDB
    WHERE
        REFCOUNTER IS NULL

    UNION ALL

    SELECT
        CTE.Lvl + 1 AS Lvl,
        CTE.OriginalBELNR,
        CTE.OriginalCHARGE_HOLD,
        CTE.OriginalCOUNTER,
        CTE.OrginalREFCOUNTER,
        CATSDB.BELNR AS NewBELNR,
        CATSDB.CHARGE_HOLD AS NewCHARGE_HOLD,
        CATSDB.[COUNTER] AS NewCOUNTER,
        CATSDB.REFCOUNTER AS NewREFCOUNTER
    FROM
        CATSDB
        INNER JOIN CTE ON CATSDB.REFCOUNTER = CTE.NewCOUNTER
)
SELECT * FROM CTE;

Промежуточный результат

+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+
| Lvl | OriginalBELNR | OriginalCHARGE_HOLD | OriginalCOUNTER | OrginalREFCOUNTER | NewBELNR  |   NewCHARGE_HOLD    | NewCOUNTER | NewREFCOUNTER |
+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+
|   1 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417548605 | T4-GS023ABC2 0150#* |  420202428 | NULL          |
|   2 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417549506 | T4-GS023-ABC2       |  420203329 | 420202428     |
|   3 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417553156 | JGS023001    0010#* |  420206979 | 420203329     |
|   4 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417557221 | T4-GS023-ABC2       |  420211044 | 420206979     |
|   5 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417581675 | JGS023001    0010#* |  420235498 | 420211044     |
|   6 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417677969 | JGS023001    0010#* |  420331792 | 420235498     |
+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+

Как видите, мы взяли начальную строку цепочки (где RefCounter is NULL) и перенесли ее на всю цепочку изменений.

Теперь нам просто нужно выбрать строки с последним изменением, то есть с наибольшим Lvl для каждой начальной строки. Один из способов сделать это — использовать функцию ROW_NUMBER с подходящим разделением.

Последний запрос

WITH
CTE
AS
(
    SELECT
        1 AS Lvl,
        CATSDB.BELNR AS OriginalBELNR,
        CATSDB.CHARGE_HOLD AS OriginalCHARGE_HOLD,
        CATSDB.[COUNTER] AS OriginalCOUNTER,
        CATSDB.REFCOUNTER AS OrginalREFCOUNTER,
        CATSDB.BELNR AS NewBELNR,
        CATSDB.CHARGE_HOLD AS NewCHARGE_HOLD,
        CATSDB.[COUNTER] AS NewCOUNTER,
        CATSDB.REFCOUNTER AS NewREFCOUNTER
    FROM
        CATSDB
    WHERE
        REFCOUNTER IS NULL

    UNION ALL

    SELECT
        CTE.Lvl + 1 AS Lvl,
        CTE.OriginalBELNR,
        CTE.OriginalCHARGE_HOLD,
        CTE.OriginalCOUNTER,
        CTE.OrginalREFCOUNTER,
        CATSDB.BELNR AS NewBELNR,
        CATSDB.CHARGE_HOLD AS NewCHARGE_HOLD,
        CATSDB.[COUNTER] AS NewCOUNTER,
        CATSDB.REFCOUNTER AS NewREFCOUNTER
    FROM
        CATSDB
        INNER JOIN CTE ON CATSDB.REFCOUNTER = CTE.NewCOUNTER
)
,CTE_rn
AS
(
    SELECT
        *
        ,ROW_NUMBER() OVER (PARTITION BY OriginalCOUNTER ORDER BY Lvl DESC) AS rn
    FROM CTE
)
SELECT *
FROM CTE_rn
WHERE rn = 1
--OPTION (MAXRECURSION 0)
;

Если у вас может быть цепочка длиннее 100, вы должны добавить OPTION (MAXRECURSION 0) к запросу, потому что по умолчанию SQL Server ограничивает глубину рекурсии до 100.

Результат

+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+----+
| Lvl | OriginalBELNR | OriginalCHARGE_HOLD | OriginalCOUNTER | OrginalREFCOUNTER | NewBELNR  |   NewCHARGE_HOLD    | NewCOUNTER | NewREFCOUNTER | rn |
+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+----+
|   6 |     417548605 | T4-GS023ABC2 0150#* |       420202428 | NULL              | 417677969 | JGS023001    0010#* |  420331792 |     420235498 |  1 |
+-----+---------------+---------------------+-----------------+-------------------+-----------+---------------------+------------+---------------+----+

Эффективность

Чтобы он работал эффективно, нам нужен индекс для столбца REFCOUNTER. Кроме того, запрос предполагает, что REFCOUNTER равно NULL, а не ''. Если у вас есть смесь NULL и пустых строк, унифицируйте свои данные, иначе индекс будет бесполезен. Этот индекс является минимумом того, что вам нужно иметь.

В идеале у вас должен быть CLUSTERED индекс для столбца REFCOUNTER, потому что запрос всегда выбирает все столбцы из таблицы.

CREATE CLUSTERED INDEX [IX_RefCounter] ON [dbo].[CATSDB]
(
    [REFCOUNTER] ASC
)

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

У меня есть довольно хороший план с этим кластеризованным индексом.

план

person Vladimir Baranov    schedule 27.08.2019
comment
Позвольте мне изучить это. Извините, что не вернулся к вашим вопросам в ОП. На этой неделе я отвлекся на что-то другое, и у меня не было возможности вернуться к этому. Я также собираюсь упростить свой OP и добавить больше данных. Стоять рядом с. Может не сразу - person dk96m; 30.08.2019
comment
Хорошо, так что это будет работать для моей начальной загрузки моей таблицы из таблицы кошек. НО, после этого я буду выбирать только данные изcatsdb, где последняя измененная дата будет после последнего запуска, поэтому ему не придется просматривать миллиарды строк, а только те, которые являются новыми или измененными с момента последний запуск. Имеет ли это смысл. Вот почему я получаю таблицу счетчиков ссылок, чтобы иметь возможность отслеживать все значения счетчика/счетчика ссылок. - person dk96m; 30.08.2019
comment
Обновлен OP, чтобы иметь меньше столбцов и больше данных. - person dk96m; 31.08.2019
comment
Поэтому я думаю, что я собираюсь перенести эти данные в локальную таблицу. Должен ли быть кластеризованный индекс для счетчика и счетчика ссылок или только для счетчика ссылок? - person dk96m; 31.08.2019
comment
Я не совсем понимаю, что вам нужно. Запрос в этом ответе также возвращает ожидаемые результаты для обновленных выборочных данных. За исключением одной строки со СЧЕТЧИКОМ = 000429774620. Данные выборки содержат три строки в этой цепочке, но похоже, что результат выборки рассчитывается так, как если бы их было только две. Скорее всего, обработка вашего полного набора данных по этому запросу займет менее 9 дней, но вам придется попробовать себя и сравнить производительность. Я думаю, что идеальный индекс был бы таким, как я написал в ответе. - person Vladimir Baranov; 31.08.2019
comment
Если вам нужен метод для периодического эффективного обновления набора результатов, это совсем другая проблема. Вы лучше задайте другой вопрос и покажите хорошие наборы выборочных данных - исходные, плюс какой результат вам от этого нужен; затем пакет добавленных строк, а также то, как изменится ваш ожидаемый результат. Если запрос, который всегда обрабатывает весь набор данных, достаточно быстр, вам может не понадобиться усложнять его. - person Vladimir Baranov; 31.08.2019
comment
Да, есть моя начальная загрузка данных. Затем, продвигаясь вперед, я буду извлекать данные из источника данных только для строк, которые изменились с момента последнего запуска. - person dk96m; 03.09.2019

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

Преобразование COUNTER и REFCOUNTER в тип данных int из nvarchar, операции с int выполняются намного быстрее, чем с символами. Не используйте курсоры, вы все равно можете обрабатывать одну запись за раз, используя цикл while.

DECLARE @CCOUNTER int = 0
WHILE (1 = 1)
BEGIN
    /* SELECT @COUNTER = MIN(COUNTER) > @COUNTER FROM CATSDB */
    /* IF @@ROWCOUNT != 1 THEN BREAK OUT OF THE WHILE LOOP, WE ARE DONE */
    /* SELECT RECORD FOR THIS @COUNTER FROM CATSDB */
    /* DO THE PROCESSING FOR THIS RECORD */
END
person Neeraj Agarwal    schedule 31.08.2019
comment
Должен ли я по-прежнему объявлять все переменные столбца и в цикле while выбирать эти переменные для их обработки? - person dk96m; 03.09.2019

Существует метод, называемый sql Bulk copy. Я не помогу в вашей проблеме, но попробуйте.

person amaldec23    schedule 02.09.2019

Самый эффективный способ сделать это через BCP. https://docs.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-2017.

Вы можете перенести все данные в промежуточную таблицу в SQL Server, а затем запустить вставки и обновления. Также при проверке на отсутствие записи определить, вставка это или обновление "ЕСЛИ НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ * ИЗ ВРЕМЕННОГО ГДЕ [СЧЕТЧИК] = @СЧЕТЧИК)" очень накладно.

Пример более эффективного способа сделать это: (Имена таблиц TBL_SOURCE, TBL_DESTINATION, #TBL_UPDATES и #TBL_INSERTS. >)

SELECT * into #TBL_INSERTS
FROM TBL_SOURCE S
    left outer join TBL_DESTINATION D on S.COUNTER=D.COUNTER
WHERE D.Counter is null

SELECT * into #TBL_UPDATES
FROM TBL_SOURCE S
    left outer join TBL_DESTINATION D on S.COUNTER=D.COUNTER
WHERE D.Counter is not null

Обновления будут записываться в #tbl_updates и вставляться в #tbl_inserts.

person Igor Stavnitser    schedule 02.09.2019

Посмотрите на основе нескольких примеров данных и данных вывода, наш скрипт не может быть на 100% исправным и оптимизированным, когда речь идет об обновлении миллионов данных.

Я уверен в своем сценарии, что его можно улучшить в этом направлении после полного понимания требований.

Прежде всего, мне интересно, почему тип данных nvarchar, если возможно, сделайте его varchar,int,datetime.

Если вы можете изменить тип данных, то это удивит производительность.

Также нет столбца идентификаторов, который должен быть Clustered Index.

Эти два пункта имеют значение с точки зрения производительности.

Итак, в моем примере

CREATE TABLE CATSDB 
        (
            id int identity ,
            [COUNTER] nvarchar(12),
            REFCOUNTER nvarchar(12),
            PERNR nvarchar(8),
            WORKDATE nvarchar(8),
            CATSHOURS decimal(7, 3),
            APDAT nvarchar(8),
            LAETM nvarchar(6),
            CATS_STATUS nvarchar(2),
            APPR_STATUS nvarchar(2)
        )   

ALTER TABLE CATSDB
ADD CONSTRAINT PK_CATSDB_ID PRIMARY KEY CLUSTERED(ID)

CREATE NONCLUSTERED INDEX FICATSDB_REFCOUNTER ON CATSDB(REFCOUNTER,[COUNTER]);




IF OBJECT_ID('tempdb..#TEMP', 'U') IS NOT NULL
    DROP TABLE #TEMP;

CREATE TABLE #TEMP
(UpdateID      INT,
 FINDID        INT
 PRIMARY KEY,
 [COUNTER]     [NVARCHAR](12) NOT NULL,
 [REFCOUNTER]  [NVARCHAR](12) NULL,
 [PERNR]       [NVARCHAR](8) NULL,
 [WORKDATE]    [NVARCHAR](8) NULL,
 [CATSHOURS]   [DECIMAL](7, 3) NULL,
 [APDAT]       [NVARCHAR](8) NULL,
 [LAETM]       [NVARCHAR](6) NULL,
 [CATS_STATUS] [NVARCHAR](2) NULL,
 [APPR_STATUS] [NVARCHAR](2) NULL
);

WITH CTE
     AS (SELECT a.id,
                a.[COUNTER],
                a.REFCOUNTER,
                a.id AS Findid
         FROM dbo.CATSDB A

         UNION ALL
         SELECT b.id,
                a.[COUNTER],
                a.[refCOUNTER],
                a.id
         FROM dbo.CATSDB A
              INNER JOIN CTE b ON(a.REFCOUNTER = b.[COUNTER])
         WHERE a.id >= b.Findid),
     CTE1
     AS (SELECT id,
                MAX(Findid) Findid
         FROM CTE
         GROUP BY id)

     INSERT INTO #TEMP
     (UpdateID,
      FINDID,
      [COUNTER],
      [REFCOUNTER],
      [PERNR],
      [WORKDATE],
      [CATSHOURS],
      [APDAT],
      [LAETM],
      [CATS_STATUS],
      [APPR_STATUS]
     )
            SELECT c1.ID,
                   c1.FINDID,
                   a.COUNTER,
                   a.REFCOUNTER,
                   a.PERNR,
                   a.WORKDATE,
                   a.CATSHOURS,
                   a.APDAT,
                   a.LAETM,
                   a.CATS_STATUS,
                   a.APPR_STATUS
            FROM dbo.CATSDB A
                 INNER JOIN CTE1 c1 ON a.id = c1.Findid;

BEGIN TRY
    BEGIN TRAN;

    UPDATE A
      SET
          [REFCOUNTER] = b.REFCOUNTER,
          [PERNR] = b.PERNR,
          [WORKDATE] = b.WORKDATE,
          [CATSHOURS] = b.CATSHOURS,
          [APDAT] = b.APDAT,
          [LAETM] = b.LAETM,
          [CATS_STATUS] = b.CATS_STATUS,
          [APPR_STATUS] = b.APPR_STATUS
    FROM CATSDB A
         INNER JOIN #TEMP B ON a.id = b.UpdateID;

    -- this is only test query
    SELECT c1.UpdateID AS UpdateID,
           a.*
    FROM dbo.CATSDB A
         INNER JOIN #TEMP c1 ON a.id = c1.Findid;

    IF(@@trancount > 0)
        ROLLBACK; -- commit
END TRY
BEGIN CATCH
    IF(@@trancount > 0)
        ROLLBACK;
END CATCH;

#Temp should be permanent table.

IMO, вашей таблице очень нужен столбец идентификаторов, который должен быть идентификатором и кластерным индексом.

Вы можете попробовать, вы можете изменить его.

REFCOUNTER,COUNTER должен быть некластеризованным индексом.

После и только после оптимизации запроса и при правильном ПЛАНЕ выше индекс повысит производительность.

Правильный ПЛАН: следует ли вам использовать Recursive or RBAR и обновлять миллионы записей за один раз или мне следует Batch update?

Вы можете сначала протестировать сценарий с миллионами строк с помощью Rollback.

person KumarHarsh    schedule 11.09.2019
comment
counter будет первичным ключом. - person dk96m; 17.09.2019
comment
Catsdb — это исходные данные. Я буду еженедельно извлекать данные из этого источника, чтобы вставлять или обновлять свою таблицу. Новые записи будут иметь нулевое/пустое поле счетчика ссылок. Обновленные записи будут иметь счетчик ссылок. Это может выглядеть так: Counter/refcounter 1/NULL, 2/1, 3/2, 4/3. Это все 1 запись. Счетчик 1 был исходным, Счетчик 2 был обновлен до 1, Счетчик 2 теперь является обновленной записью. Затем 3 обновляет 2 и 3 становится обновленной записью. 4 обновления 3 и 4 становятся рекордными. Последняя запись, которую я хочу показать, будет 1 с обновлениями из 4. - person dk96m; 17.09.2019
comment
Кроме того, в моей таблице уже могут быть счетчики 1 и 2, а на следующей неделе появятся 3 и 4. Имеет ли это смысл? - person dk96m; 17.09.2019
comment
refcounter не может быть нулевым все время - person dk96m; 18.09.2019
comment
@ dk96m, вы ничего не сказали о моем существующем ответе. Если мы говорим только о выводе, то я думаю, что часть вывода верна. Разве это не так. Я вернусь к вам с моим обновленным сценарием после вашего отзыва - person KumarHarsh; 19.09.2019
comment
Хорошо, я смотрю на запрос, смотрю, как он работает, когда я его использую. Столбец идентификаторов на самом деле является COUNTER. Это будет уникально. Кроме того, дело не только в том, где refcounter равен нулю. Исходная запись будет иметь нулевой счетчик ссылок, но когда появится запись обновления, эта исходная запись должна быть обновлена ​​всем из записи обновления, кроме исходного значения счетчика. Итак, скажем, начальный счетчик/счетчик ссылок равен 1/NULL, тогда, когда запись обновления поступает со счетчиком/счетчиком ссылок 4/1, она обновит исходную запись, которая теперь будет иметь счетчик/счетчик ссылок 1/1. - person dk96m; 19.09.2019
comment
если приходит третья запись обновления со счетчиком/счетчиком ссылок 8/4, то она обновит исходную запись и будет равна 1/4. Надеюсь, это имеет смысл. Только первая запись будет иметь нулевой счетчик ссылок. Никакого обновления после этого не будет, если только мы не обновим исходную запись со значением refcounter, просто все остальное - person dk96m; 19.09.2019