Может ли этот построчный скрипт T-SQL быть преобразован в скрипт на основе набора? - PullRequest
1 голос
/ 06 сентября 2010

Я написал этот сценарий T-SQL для скручивания дублирующихся строк в базе данных, созданных в процессе реконструкции.Для этого он выполняет следующие действия:

  • Получает и сохраняет минимальный первичный ключ целевой таблицы (ColTargetPK) для набора повторяющихся записей в табличной переменной (@minColTargetPKTable);определение дубликатов путем сопоставления по трем столбцам - ColIntA, ColIntB и ColDateTimeA.
  • Устанавливает столбец назначения, который будет свернут (TargetColVarchar), равным объединению целевого столбца соответствующих повторяющихся записей.
  • Помечает дубликаты записей как неактивные (ColTargetStatus = 0)
  • Сообщает об успехе (или сбое)

Из-за размера используемого набора данных этот сценарий занимает неподходящее времябежать.

Может кто-нибудь увидеть, как это можно преобразовать в наборы, если да, не могли бы вы привести пример?

Заранее извиняюсь, если мое описание немного сбивает с толку ...

declare @MinColTargetPKTable table
    (ColIntA int,
     ColIntB int,
     ColDateTimeA nvarchar(25),
     minColTargetPK int
    )

insert @minColTargetPKtable
    select ColIntA, ColIntB, convert(nvarchar(25),ColDateTimeA,120) as ColDateTimeA, 
    min(ColTargetPK) as MinColTargetPK from TargetColTable
    group by ColIntA, ColIntB, convert(nvarchar(25),ColDateTimeA,120) 


declare @TargetColVarchar varchar(max)

declare @updatedColTargetPKs table
(updatedColTargetPKs int)

declare @minColTargetPK int

declare cur cursor
for
select minColTargetPK
from @minColTargetPKtable

open cur

fetch next from cur into @minColTargetPK

while @@FETCH_STATUS = 0
begin
    begin try

    set @TargetColVarchar =
        convert(nvarchar(max),(
        select replace(convert(nvarchar(max), isnull(TargetColVarchar,'')) +   convert (nvarchar(max),' \par \par \par'), '\par } ', '\par') as 
        TargetColVarchar
        from TargetColTable v1
        where ColIntA = (select ColIntA from TargetColTable where ColTargetPK = @minColTargetPK)
        and ColIntB = (select ColIntB from TargetColTable where ColTargetPK = @minColTargetPK)
        and convert(nvarchar(25),ColDateTimeA,120) = (select convert(nvarchar(25),ColDateTimeA,120) from TargetColTable where ColTargetPK = @minColTargetPK)
        order by ColTargetPK
        for xml path(''), type  
        ))

        set @TargetColVarchar = REPLACE(REPLACE (REPLACE (@TargetColVarchar,'<TargetColVarchar>',''),'</TargetColVarchar>',''), '&#x0D;','')


        update TargetColTable
        set TargetColVarchar = @TargetColVarchar
        where ColTargetPK = @minColTargetPK

        update TargetColTable
        set ColTargetStatus = 0
        from TargetColTable v1
        where ColIntA = (select ColIntA from TargetColTable where ColTargetPK = @minColTargetPK)
        and ColIntB = (select ColIntB from TargetColTable where ColTargetPK = @minColTargetPK)
        and convert(nvarchar(25),ColDateTimeA,120) = (select convert(nvarchar(25),ColDateTimeA,120) from TargetColTable where ColTargetPK = @minColTargetPK)
        and ColTargetPK != @minColTargetPK

        Print 'Merge complete for ColTargetPK '+ convert(varchar(50),  @minColTargetPK)

    end try
    begin catch

        Print 'Merge failed for ColTargetPK '+ convert (varchar(20),@minColTargetPK)

    end catch

    fetch next from cur into @minColTargetPK
end

close cur
deallocate cur

РЕДАКТИРОВАТЬ: Хорошо, ниже приведен сценарий, перемещенный в операцию на основе набора по предложению Преета.Чтобы дать некоторый дополнительный фон, TargetTable составляет приблизительно 1,1 миллиона строк.Как ни странно, приведенный ниже сценарий на основе наборов не является значительно более быстрым, чем сценарий на основе курсора, приведенный ниже, в одном и том же подмножестве данных (около 20000 строк) в течение 2 испытаний.Любые мысли о том, почему это не будет быстрее?

declare @minColTargetPKTable table
    (
    ColIntA int,
    ColIntB int,
    ColDateTimeA nvarchar(25),
    ColTargetPK int,
    concTargetCol varchar(max)
    )

insert @minColTargetPKtable (minColIntA,ColIntB,minColDateTimeA,minColTargetPK)
select ColIntA, ColIntB, convert(nvarchar(25),ColDateTimeA,120) as ColDateTimeA, min(ColTargetPK) as minColTargetPK from TargetTable
group by ColIntA, ColIntB, convert(nvarchar(25),ColDateTimeA,120) 


update @minColTargetPKTable 
set concTargetCol  = 
(REPLACE(REPLACE(REPLACE(replace(convert(nvarchar(max),
    (
        select convert(nvarchar(max), isnull(TargetColVarchar,'')) + convert (nvarchar(max),' \par \par \par ') as 
        TargetColVarchar
        from TargetTable v1
        where ColIntA = (select ColIntA from TargetTable where ColTargetPK = minColTargetPK)
        and ColIntB = (select ColIntB from TargetTable where ColTargetPK = minColTargetPK)
        and convert(nvarchar(25),ColDateTimeA,120) = (select convert(nvarchar(25),ColDateTimeA,120) from TargetTable where ColTargetPK = minColTargetPK)
        order by ColTargetPK
        for xml path(''), type  
    ))
, '\par } ', '\par '),'<TargetColVarchar>',''),'</TargetColVarchar>',''), '&#x0D;',''))

update TargetTable 
set TargetColVarchar = mv.concTargetCol
from @minColTargetPKTable mv
where mv.minColTargetPK = TargetTable.ColTargetPK 

update TargetTable 
set TargetColStatus = 0 
from TargetTable v
inner join @minColTargetPKTable mv on
mv.minColIntA = v.ColIntA
and mv.minColDateTimeA = convert(nvarchar(25),v.ColDateTimeA,120)
and mv.ColIntB = v.ColIntB 
where ColTargetPK not in (select minColTargetPK from @minColTargetPKTable)

Ответы [ 2 ]

1 голос
/ 06 сентября 2010

Хорошо, я бы предложил следующее:

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

Затем вы можете оптимизировать на основе планов выполнения

Обновление:

Глядя на ваши исправленные результаты, я бы сказал, что по порядку:

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

а. добавьте больше столбцов в временную таблицу для записи таких вещей, как: (select ColIntA from TargetColTable where ColTargetPK = @minColTargetPK и (select ColIntB from TargetColTable where ColTargetPK = @minColTargetPK в самом начале

б. Заменить строку медленно, я считаю. Это все еще будет медленным. Я знаю, что XML не самая быстрая вещь в мире. Можете ли вы заменить строку comp на специальный XML-код SQL

с. Во втором обновлении внизу where ColTargetPK not in (select minColTargetPK from @minColTargetPKTable), вероятно, будет медленнее, чем точное соединение, и вы должны выполнить оба обновления за один удар

Однако используйте Фактический план запроса, чтобы решить это.

0 голосов
/ 06 сентября 2010

Попробуйте сделать это со своим первым запросом

    from tct v1
    join tct v2 on v2.pk = @pk
    where v1.a = v2.a and v1.b = v2.b and v1.dt = v2.dt

и это со вторым запросом

    from tct v1
    join tct v2 on v2.pk = @pk and v1.pk <> @pk
    where v1.a = v2.a and v1.b = v2.b and v1.dt = v2.dt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...