18

数千のレコードを含む毎日のXMLファイルを受け取ります。各レコードは、レポートと請求に使用するために内部データベースに保存する必要のあるビジネストランザクションです。毎日のファイルには一意のレコードしか含まれていないという印象を受けましたが、一意の定義がプロバイダーの定義とまったく同じではないことがわかりました。

このデータをインポートする現在のアプリケーションはC#.Net 3.5コンソールアプリケーションです。これは、列がXMLレコードの構造と完全に一致するMS SQLServer2008データベーステーブルにSqlBulkCopyを使用してインポートします。各レコードには100を超えるフィールドがあり、データには自然キーがありません。つまり、複合キーとして意味をなすことができるフィールドは、nullも許可する必要があります。現在、テーブルにはいくつかのインデックスがありますが、主キーはありません。

基本的に、行全体が一意である必要があります。1つのフィールドが異なる場合、挿入するのに十分有効です。行全体のMD5ハッシュを作成し、それをデータベースに挿入し、制約を使用してSqlBulkCopyが行を挿入しないようにすることを検討しましたが、MD5ハッシュをBulkCopy操作に取り込む方法がわかりません。操作全体が失敗し、いずれかのレコードが失敗した場合にロールバックするか、それとも続行するかを確認します。

このファイルには非常に多くのレコードが含まれており、XMLで行ごとに移動し、すべてのフィールドに一致するレコードをデータベースに照会してから、挿入を決定することが、これを実行できる唯一の方法です。アプリケーションを完全に書き直す必要がないことを望んでいただけで、一括コピー操作は非常に高速です。

主キーなしで行の重複を防ぎながらSqlBulkCopyを使用する方法を知っている人はいますか?または、これを行うための別の方法についての提案はありますか?

4

7 に答える 7

17

データをステージングテーブルにアップロードし、その後、ファイナルテーブルにコピーして重複を処理します。

たとえば、ステージングテーブルに(一意ではない)インデックスを作成して、「キー」を処理できます。

于 2010-04-07T15:26:47.207 に答える
7

SQL 2008 を使用していることを考えると、アプリケーションを大幅に変更する必要なく簡単に問題を解決するための 2 つのオプションがあります (まったく変更する必要はありません)。

最初に考えられる解決策は、最初のテーブルのような 2 番目のテーブルを作成することですが、重複を排除するという面倒な作業をすべて実行する ignore_dup_key オプションを使用して、代理 ID キーと一意性制約が追加されます。

SSMS で実行して何が起こっているかを確認できる例を次に示します。

if object_id( 'tempdb..#test1' ) is not null drop table #test1;
if object_id( 'tempdb..#test2' ) is not null drop table #test2;
go


-- example heap table with duplicate record

create table #test1
(
     col1 int
    ,col2 varchar(50)
    ,col3 char(3)
);
insert #test1( col1, col2, col3 )
values
     ( 250, 'Joe''s IT Consulting and Bait Shop', null )
    ,( 120, 'Mary''s Dry Cleaning and Taxidermy', 'ACK' )
    ,( 250, 'Joe''s IT Consulting and Bait Shop', null )    -- dup record
    ,( 666, 'The Honest Politician', 'LIE' )
    ,( 100, 'My Invisible Friend', 'WHO' )
;
go


-- secondary table for removing duplicates

create table #test2
(
     sk int not null identity primary key
    ,col1 int
    ,col2 varchar(50)
    ,col3 char(3)

    -- add a uniqueness constraint to filter dups
    ,constraint UQ_test2 unique ( col1, col2, col3 ) with ( ignore_dup_key = on )
);
go


-- insert all records from original table
-- this should generate a warning if duplicate records were ignored

insert #test2( col1, col2, col3 )
select col1, col2, col3
from #test1;
go

別の方法として、2 番目のテーブルを使用せずに重複をインプレースで削除することもできますが、ニーズに対してパフォーマンスが遅すぎる可能性があります。その例のコードは次のとおりで、SSMS でも実行できます。

if object_id( 'tempdb..#test1' ) is not null drop table #test1;
go


-- example heap table with duplicate record

create table #test1
(
     col1 int
    ,col2 varchar(50)
    ,col3 char(3)
);
insert #test1( col1, col2, col3 )
values
     ( 250, 'Joe''s IT Consulting and Bait Shop', null )
    ,( 120, 'Mary''s Dry Cleaning and Taxidermy', 'ACK' )
    ,( 250, 'Joe''s IT Consulting and Bait Shop', null )    -- dup record
    ,( 666, 'The Honest Politician', 'LIE' )
    ,( 100, 'My Invisible Friend', 'WHO' )
;
go


-- add temporary PK and index

alter table #test1 add sk int not null identity constraint PK_test1 primary key clustered;
create index IX_test1 on #test1( col1, col2, col3 );
go


-- note: rebuilding the indexes may or may not provide a performance benefit

alter index PK_test1 on #test1 rebuild;
alter index IX_test1 on #test1 rebuild;
go


-- remove duplicates

with ranks as
(
    select
         sk
        ,ordinal = row_number() over 
         ( 
            -- put all the columns composing uniqueness into the partition
            partition by col1, col2, col3
            order by sk
         )
    from #test1
)
delete 
from ranks
where ordinal > 1;
go


-- remove added columns

drop index IX_test1 on #test1;
alter table #test1 drop constraint PK_test1;
alter table #test1 drop column sk;
go
于 2010-04-08T04:13:12.617 に答える
5

Primary Keyの代わりに単純に使用して、 Indexを作成して設定しないのはなぜですか

Ignore Duplicate Keys: YES

これにより、重複するキーがエラーを発生させるのを防ぎ、作成されません (既に存在するため)。

ここに画像の説明を入力

私はこの方法を使用して、1 日あたり約 120.000 行を挿入し、問題なく動作します。

于 2012-12-21T20:56:04.553 に答える
4

一時テーブルに一括コピーしてから、そこから実際の宛先テーブルにデータをプッシュします。このようにして、SQLを使用して重複をチェックおよび処理できます。

于 2010-04-07T15:25:44.910 に答える
1

データ量はどれくらいですか?私が見ることができる2つのオプションがあります:

IDataReader1:独自に実装し、データに対してハッシュを使用し、重複をスキップしてTDSに渡されないようにすることで、ソースでフィルタリングします。

2:DBでフィルタリングします。最も単純なレベルでは、インポートの複数の段階(未加工のサニタイズされていないデータ)を作成してから、必要に応じて中間テーブルを使用して、DISTINCTデータを実際のテーブルにコピーできると思います。これのいくつかに使用したいかもしれませんが、それは状況によって異なります。CHECKSUM

于 2010-04-07T15:29:17.510 に答える
1

そして、そのテーブルを修正します。できれば PK として、一意のインデックスを持たないテーブルを作成することはできません。自然キーがないために代理キーを追加する場合でも、特定のレコードを明確に識別できる必要があります。そうでなければ、すでに持っている重複をどのように取り除きますか?

于 2010-04-07T17:09:22.700 に答える
0

これでだいぶすっきりしたと思います。

var dtcolumns = new string[] { "Col1", "Col2", "Col3"};

var dtDistinct = dt.DefaultView.ToTable(true, dtcolumns);

using (SqlConnection cn = new SqlConnection(cn) 
{
                copy.ColumnMappings.Add(0, 0);
                copy.ColumnMappings.Add(1, 1);
                copy.ColumnMappings.Add(2, 2);
                copy.DestinationTableName = "TableNameToMapTo";
                copy.WriteToServer(dtDistinct );

}

この方法では、必要なデータベース テーブルは 1 つだけで、ビジネス ロジックをコード内に保持できます。

于 2010-12-17T14:26:59.233 に答える