Параллельное создание пользовательских номеров SQL Server для POS - PullRequest
0 голосов
/ 10 февраля 2019

Я работаю над переписыванием хранимой процедуры в SQL Server 2008, которая используется в процессе выставления счетов POS.Первый шаг - получить номер счета, который представляет собой автоматический поворот порядкового номера с добавленным префиксом.

По мере того, как количество одновременно работающих терминалов растет ~ 10-30, мы столкнулись с рядом проблем, таких как дублирование номера, блокировка блокировки.Оптимизация, над которой я сейчас работаю, получена из здесь , которая улучшена до расширенного (без дубликатов).Но когда я попытался протестировать с SQLQueryStress на основе этого предложения с использованием 10 итераций и 10 параллельных потоков, я увидел мертвую блокировку в нескольких тестах и ​​непоследовательный сбой, получая префикс из той же таблицы дляпервая (несколько итераций)

Procudure имеет эти в настоящее время

  1. УСТАНОВИТЬ УРОВЕНЬ ИЗОЛЯЦИИ SERIALIZABLE
  2. получить префикс из той же таблицы с помощью (nolock)где type = @ type и Terminalid = @ Terminalid
  3. Начало Tran
  4. ОБНОВЛЕНИЕ Нумерация с (сериализуемым) SET @ nextval = следующий номер, следующий номер = следующий номер + 1
  5. если @@rowcount = 0 insert
  6. Commit tran
  7. output Префикс формата + @ nextval

Примечание, Этот фрагмент кода не будетИдеально, так как я собирался перестроить это.Это только часть кода if if, где else имеет один и тот же блок, повторяющийся с различным условием where (для четырех разных сценариев).

ALTER PROCEDURE [dbo].[GetnextNumberTest] 
        @transType varchar(50), -- 
        @terminalaname varchar(50)='',  --will be empty if it is not terminal wise
        @nextvalue varchar(10) output
AS
BEGIN

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

declare @ResetBasedOn int =0
        ,@Prefix varchar(50)=''
        ,@nextvalint int=0


select  @ResetBasedOn=RestartOn,
        @Prefix=((SELECT Prefix FROM TerminalMaster(nolock) WHERE TerminalName=@terminalaname)+'/'+ prefix)
                        from NumberingSchemeTest (nolock)
    where  TRSType= @transType 
        and (TerminalName=@terminalaname or TerminalName='') and active=1


if(@ResetBasedOn=0) --daily
begin

    Begin Tran
        UPDATE Numberingschemetest with (serializable)      
            SET @nextvalint=nextnumber,
            -- 
                nextnumber = nextnumber + 1

        WHERE TRSType= @transType 
            and (TerminalName=@terminalaname or TerminalName='') 
            and yearlydate =convert(varchar, GETDATE()) 
            and active=1 

       if @@rowcount = 0
       begin
            UPDATE Numberingschemetest with (serializable)  
                set active=0
            where  TRSType= @transType 
                and (TerminalName=@terminalaname or TerminalName='') 
                and yearlydate =convert(varchar, GETDATE() -1) 
                and active=1

            insert into  Numberingschemetest (
                TRSType,  
                Prefix,    
                TPrefix,   
                TerminalName,  
                RestartOn, 
                YearlyDate,  
                StartingFrom, 
                NextNumber, 
                active,PreparedBy
                )
            (select top 1  
                TRSType,  
                Prefix,    
                TPrefix,   
                TerminalName,  
                RestartOn,   
                convert(varchar, GETDATE()),  
                StartingFrom, 
                StartingFrom+1, 
                1  ,@terminalaname
            from Numberingschemetest 
                where TRSType= @transType 
                    and (TerminalName=@terminalaname or TerminalName='') 
                    and active=0 )

        End
    Commit Tran
    if(@nextvalint=0)
        set  @nextvalue=@Prefix+'0001' 
    else
    set @nextvalue =@Prefix+RIGHT('000'+ CAST(@nextvalint AS VARCHAR(50)),Case when LEN(@nextvalint)>4 then LEN(@nextvalint) else 4 end)
End

Все это основано на нескольких похожих вопросах с этого сайта,На этом этапе я мог думать только о двух вещах.Один разделит префикс на отдельную таблицу, а другой - попробовать другой инструмент для проведения нагрузочного тестирования.

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

...