大きなテーブルから重複する行を削除する必要があります。それを達成するための最良の方法は何ですか?
現在私はこのアルゴリズムを使用しています:
declare @t table ([key] int )
insert into @t select 1
insert into @t select 1
insert into @t select 1
insert into @t select 2
insert into @t select 2
insert into @t select 3
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 6
insert into @t select 6
insert into @t select 6
insert into @t select 7
insert into @t select 7
insert into @t select 8
insert into @t select 8
insert into @t select 9
insert into @t select 9
insert into @t select 9
insert into @t select 9
insert into @t select 9
select * from @t
; with cte as (
select *
, row_number() over (partition by [Key] order by [Key]) as Picker
from @t
)
delete cte
where Picker > 1
select * from @t
私のシステムで実行すると:
;WITH Customer AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY AccountCode ) AS [Version]
FROM Stage.Customer
)
DELETE
FROM Customer
WHERE [Version] <> 1
<> 1は> 1より優れていることがわかりました。
私はこのインデックスを作成できましたが、現在は存在しません:
USE [BodenDWH]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [Stage].[Customer] ([AccountCode])
INCLUDE ([ID])
GO
これを行う他の方法はありますか?
この場合、このテーブルは大きくありません-ライブシステムで約500,000レコード。
削除はSSISパッケージの一部であり、毎日実行され、1日あたり約10〜15個のレコードが削除されます。
データの構造に問題があります。顧客ごとに1つのAccountCodeが必要ですが、重複があり、それらが削除されない場合、後の段階でパッケージが破損します。
パッケージを開発したのは私ではなく、私の設計範囲は何も再設計しないことです。
私は、インデックスの作成や何かを参照する必要なく、T-SQLコードだけで、重複を取り除くための最善の方法の直後にいます。
テーブルが小さく、削除する行数が少ない場合は、
_;WITH Customer AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY (select null) ) AS [Version]
FROM dbo.Customer
)
DELETE
FROM Customer
WHERE [Version] > 1;
_
注:上記のクエリでは、ウィンドウ順序句ORDER BY (select null)
で任意の順序を使用しています( から学びました)Itzik Ben-GanのT-SQLクエリbook と@AaronBertrandは上記も引用しています)。
テーブルが大きい場合(例:5Mレコード)、 少数の行またはチャンク を削除すると、トランザクションログが膨張しないようになり、 ロックのエスカレーションが防止されます 。
ロックのエスカレーションは、Transact-SQLステートメントがテーブルの単一の参照で少なくとも5000のロックを取得した場合にのみ発生します。
_while 1=1
begin
WITH Customer AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY (select null) ) AS [Version]
FROM dbo.Customer
)
DELETE top(4000) -- choose a lower batch size than 5000 to prevent lock escalation
FROM Customer
WHERE [Version] > 1
if @@ROWCOUNT < 4000
BREAK ;
end
_