SQL перебирает 8 миллионов записей и обновляет их - PullRequest
0 голосов
/ 04 мая 2018

У меня есть таблица аудита, которая содержит около 8 миллионов записей. Недавно я добавил два новых столбца, которые мне нужно обновить из существующего столбца с некоторыми правилами / условиями. Первоначально, всякий раз, когда FK обновлялся в таблице, он сохранял старые и новые идентификаторы FK в таблице аудита. например

Table A
ID      Name
1       First A
2       Second A
3       Third A

Table B
ID   AID  Name
1     1   First B
2     1   Second B
3     2   Third B

Audit 
ID  TableName FieldName OldValue NewValue 

теперь, если я обновлю первую запись таблицы B с 1 1 Сначала B на 1 3 Сначала B, затем таблица аудита будет хранить изменения как

Audit 
ID  TableName FieldName OldValue NewValue 
1    Table B  AID        1          3

Теперь я обновил таблицу Audit, чтобы сохранить фактическое значение Text FK, т. Е. Указанное выше изменение будет сохранено как

Audit 
ID  TableName FieldName OldValue  NewValue  OldText   NewText
1    Table B   AID       1         3        First A   Third A

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

declare @sql nvarchar(max);
declare @start int = 1

while @start <= 8000000 
begin
  select top 10000  @sql = COALESCE(@sql+'Update Audit set ','Update Audit set') + 
    isnull(' OldText = ('+ dbo.GetFKText(i.TableName, i.FieldName)+case when len(isnull(i.OldValue,'')) < 1 then null else i.OldValue end +'),',' OldText = OldValue, ')  + 
    isnull(' NewText = ('+ dbo.GetFKText(i.TableName, i.FieldName)+case when len(isnull(i.NewValue,'')) < 1 then null else i.NewValue end +')',' NewText = NewValue ')    +  
    ' where AuditID = '+cast(i.AuditID as nvarchar(200))+' and lower(ltrim(rtrim(TableName))) <> ''audit'';' 
    from Audit i where i.AuditID >= @start 

  exec sp_executesql @sql

  set @start = @start+10000;
end

получить текстовую функцию (в основном я получаю столбец с именем = (TableName) + «Имя» или (TablName) + (SomeText) + «Имя» - это просто соглашение, которому я следовал во всех таблицах)

     declare @res nvarchar(max)=''; 
     declare @fn nvarchar(200);
     declare @ttn nvarchar(200);
     declare @tcn nvarchar(200);

     SELECT top 1
         @ttn = kcu.table_name  
        ,@tcn = kcu.column_name  
     FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
     INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
        ON ccu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME 
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu 
        ON kcu.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME  
     Where ccu.TABLE_NAME = @TableName and  ccu.COLUMN_NAME = @FieldName

     if isnull(@ttn,'') != '' and ISNULL(@tcn,'') != ''
     begin
       select @fn= COLUMN_NAME 
       from (SELECT top 1 COLUMN_NAME , 
                   case when COLUMN_NAME like (@ttn+'Name') then 0 
                   when COLUMN_NAME like (@ttn+'%Name') then 1 
                   when COLUMN_NAME like (@ttn+'Code') then 2 
                   when COLUMN_NAME like (@ttn+'%Code') then 3 else 4 end as CPriority
             FROM JVO.INFORMATION_SCHEMA.COLUMNS
             WHERE TABLE_NAME = @ttn and (COLUMN_NAME like '%Name' or COLUMN_NAME like '%Code'
            )
       order by CPriority) as aa; 

       RETURN 'select '+@fn+' from '+@ttn+' where '+@tcn+' = ';
     end

 return null;

Работает, но очень медленно, обновляет около 1 миллиона записей за 13 часов. Может кто-нибудь помочь улучшить этот запрос или предложить альтернативный способ его обновления.

Спасибо

...