2010-04-07 37 views
14

Tôi nhận được tệp XML hàng ngày chứa hàng nghìn bản ghi, mỗi bản ghi là giao dịch kinh doanh mà tôi cần lưu trữ trong cơ sở dữ liệu nội bộ để sử dụng trong báo cáo và thanh toán . Tôi đã có ấn tượng rằng tập tin của mỗi ngày chỉ chứa các bản ghi duy nhất, nhưng đã phát hiện ra rằng định nghĩa của tôi về duy nhất không chính xác giống như của nhà cung cấp. Ứng dụng hiện tại nhập dữ liệu này là một ứng dụng bàn điều khiển C# .Net 3.5, nó sử dụng SqlBulkCopy vào bảng cơ sở dữ liệu MS SQL Server 2008, nơi các cột khớp chính xác với cấu trúc của các bản ghi XML. Mỗi bản ghi chỉ có hơn 100 trường, và không có khóa tự nhiên trong dữ liệu, hay đúng hơn là các trường tôi có thể đưa ra có ý nghĩa như một khóa tổng hợp kết thúc cũng phải cho phép null. Hiện tại bảng có nhiều chỉ mục, nhưng không có khóa chính.Làm thế nào để ngăn chặn bản ghi trùng lặp được chèn bằng SqlBulkCopy khi không có khóa chính

Về cơ bản toàn bộ hàng cần phải là duy nhất. Nếu một trường khác, trường đó đủ hợp lệ để chèn vào. Tôi đã xem xét việc tạo một băm MD5 của toàn bộ hàng, chèn nó vào cơ sở dữ liệu và sử dụng một ràng buộc để ngăn SqlBulkCopy chèn hàng, nhưng tôi không thấy cách lấy MD5 Hash vào hoạt động BulkCopy và tôi không chắc chắn nếu toàn bộ hoạt động sẽ thất bại và quay trở lại nếu bất kỳ một bản ghi nào bị lỗi, hoặc nếu nó sẽ tiếp tục.

Tệp có chứa số lượng bản ghi rất lớn, đi từng hàng trong XML, truy vấn cơ sở dữ liệu cho bản ghi khớp với tất cả các trường và sau đó quyết định chèn thực sự là cách duy nhất tôi có thể thấy điều này. Tôi chỉ hy vọng không phải viết lại hoàn toàn ứng dụng và thao tác sao chép hàng loạt nhanh hơn rất nhiều.

Có ai biết cách sử dụng SqlBulkCopy trong khi ngăn hàng trùng lặp, không có khóa chính không? Hoặc bất kỳ đề xuất cho một cách khác nhau để làm điều này?

Trả lời

15

Tôi muốn tải dữ liệu lên bảng phân đoạn rồi xử lý các bản sao sau đó trên bản sao tới bảng cuối cùng.

Ví dụ, bạn có thể tạo một chỉ số (không duy nhất) trên bảng dàn để đối phó với những "chìa khóa"

+1

Ngoài ra, không thêm chỉ mục vào bảng dàn của bạn cho đến sau khi nhập số lượng lớn (nhanh hơn) – CResults

+0

@CResults: yes, nên đã đề cập rằng ... – gbn

+1

Điều đó chắc chắn có ý nghĩa và dễ thực hiện. Cảm ơn. – kscott

4

Tôi sẽ sao chép hàng loạt vào bảng tạm thời và sau đó đẩy dữ liệu từ đó vào bảng đích thực tế. Bằng cách này, bạn có thể sử dụng SQL để kiểm tra và xử lý các bản sao.

+0

Ý tưởng sử dụng mã băm là hấp dẫn. Chìa khóa có thể được tạo ra khỏi bảng tạm thời (nơi bạn có thể xử lý null). Mặt khác, nếu bạn có một số chỉ mục không duy nhất, bạn có thể kéo tất cả các kết quả phù hợp, nếu có, vào một số tập hợp con cột có khả năng là duy nhất hoặc gần duy nhất và chạy qua chúng để xác định tính duy nhất. – SeaDrive

1

khối lượng dữ liệu là gì? Bạn có 2 tùy chọn mà tôi có thể thấy:

1: lọc mã nguồn ở nguồn, bằng cách triển khai IDataReader của riêng bạn và sử dụng một số băm trên dữ liệu và bỏ qua bất kỳ bản sao nào để chúng không bao giờ được chuyển vào TDS.

2: lọc nó trong DB; ở mức đơn giản nhất, tôi đoán bạn có thể có nhiều giai đoạn nhập - dữ liệu thô, không được bảo vệ - và sau đó sao chép dữ liệu DISTINCT vào các bảng thực tế của bạn, có thể sử dụng bảng trung gian nếu bạn muốn. Bạn có thể muốn sử dụng CHECKSUM cho một số điều này, nhưng tùy thuộc vào điều này.

0

Và sửa bảng đó. Không có bảng nào nên không có một chỉ mục duy nhất, tốt nhất là một PK. Ngay cả khi bạn thêm khóa thay thế vì không có khóa tự nhiên, bạn cần có khả năng xác định cụ thể một bản ghi cụ thể. Nếu không, làm thế nào bạn sẽ loại bỏ các bản sao bạn đã có?

6

Vì bạn đang sử dụng SQL 2008, bạn có hai tùy chọn để giải quyết vấn đề dễ dàng mà không cần phải thay đổi nhiều ứng dụng của mình (nếu có).Giải pháp đầu tiên có thể là tạo một bảng thứ hai như bảng thứ nhất nhưng với khóa nhận dạng thay thế và một ràng buộc duy nhất được thêm vào bằng cách sử dụng tùy chọn ignore_dup_key, nó sẽ làm tất cả việc dỡ bỏ nặng các bản sao cho bạn.

Dưới đây là một ví dụ bạn có thể chạy trong SSMS để xem những gì đang xảy ra:

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 

Ngoài ra, bạn cũng có thể loại bỏ các bản sao tại chỗ mà không có một bảng thứ hai, nhưng hiệu suất có thể quá chậm đối với nhu cầu của bạn . Dưới đây là mã cho ví dụ đó, cũng có thể chạy được trong 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 
1

Tôi nghĩ rằng điều này sẽ sạch hơn rất nhiều.

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); 

} 

Cách này chỉ cần một bảng cơ sở dữ liệu và có thể duy trì Logic kinh doanh theo mã.

0

Tại sao không chỉ cần sử dụng, thay vì một Primary Key, tạo ra một Index và thiết lập

Ignore Duplicate Keys: YES 

này sẽ prevent any duplicate key to fire an error, và nó sẽ không được tạo ra (vì nó đã tồn tại).

enter image description here

tôi sử dụng phương pháp này để chèn khoảng 120.000 hàng mỗi ngày và làm việc một cách hoàn hảo.

+0

Có giới hạn khó khăn hoặc thực tế nào về số lượng trường nên được bao gồm trong chỉ mục không? Mỗi hàng dữ liệu được đề cập có trên 100 trường và mọi trường sẽ cần phải nằm trong chỉ mục. Điều này sẽ không sử dụng một số lượng tài nguyên không thực tế? – kscott

+0

Bạn cần hiểu 'chỉ số' làm gì và cho, ví dụ, tùy chọn 'Bỏ qua các khóa trùng lặp' này chỉ được áp dụng cho' document_id' và hai chỉ mục khác của tôi là những người trợ giúp để tìm kiếm có thể được truy xuất thêm nhanh chóng trên một số lượng lớn các hồ sơ như tôi tiếp tục tìm kiếm các lĩnh vực ... Nhưng phải có một giới hạn, mặc dù tôi nghĩ rằng đó là một giới hạn phần cứng (CPU + bộ nhớ) và không cơ sở dữ liệu một ... – balexandre

Các vấn đề liên quan