2013-10-28 54 views
2

我有三列的SQL Server表:最好的方式,以避免增加重複數據庫

表1

col1 int 
col2 int 
col3 string 

我對所有三列定義的唯一約束(col1, col2, col3)

現在,我有一個.csv文件,我想在該表中添加記錄,* .csv文件可以有重複的記錄。

我已經在上面的場景中搜索了各種避免重複的選項。以下是對我來說很好的三種選擇。請看看,並對每種方法的優缺點提出一些想法,以便我可以選擇最好的方法。

選項#1:

在首位避免重複而即將對象添加到從csv文件列表。我已經使用HashSet<T>,這和下面的類型T的方法重寫:

public override int GetHashCode() 
{ 
    return col1.GetHashCode() + col2.GetHashCode() + col3.GetHashCode(); 
} 

public override bool Equals(object obj) 
{ 
    var other = obj as T; 
    if (other == null) 
    { 
     return false; 
    } 
    return col1 == other.col1 
     && col2 == other.col2 
     && col3 == other.col3; 
} 

選項#2

List<T>代替HashSet<T>。所有對象之後

刪除重複加入到List<T>

List<T> distinctObjects = allObjects 
     .GroupBy(x => new {x.col1, x.col2, x.col3}) 
     .Select(x => x.First()).ToList(); 

選項#3

之後的所有對象被添加到DataTable刪除重複。

public static DataTable RemoveDuplicatesRows(DataTable dataTable) 
{ 
    IEnumerable<DataRow> uniqueRows = dataTable.AsEnumerable().Distinct(DataRowComparer.Default); 
    DataTable dataTable2 = uniqueRows.CopyToDataTable(); 
    return dataTable2; 
} 

雖然我沒有比較他們的運行時間,但我更喜歡選項#1,因爲我刪除重複的第一步 - 所以只需要什麼樣的向前邁進。

請分享你的看法,以便我可以選擇最好的一個。

非常感謝!

+1

從csv獲取數據並批量將其插入到沒有唯一約束的臨時表中,使用sql刪除重複項,然後將沒有dups的數據移動到實際的最終表中是否更有效? –

+0

^aka選項#4 – Jonesopolis

+0

如果你使用選項1,我可能會改變你的'GetHashCode'以通過素數乘以屬性,就像這個[答案](http://stackoverflow.com/a/371348/2145211) – Harrison

回答

5

我喜歡選項1:HashSet<T>提供了避免重複發送到數據庫之前的快速方法。您應該實施更好的GetHashCode,例如使用Skeet的執行從What is the best algorithm for an overridden System.Object.GetHashCode?

但有一個問題:如果表中已經包含可以是CSV的副本的數據?您必須首先將整個表格複製一個簡單的HashSet才能真正起作用。你可以做到這一點,但要解決這個問題,我可能配對選項1臨時表中,像Skip-over/ignore duplicate rows on insert的insert語句:

INSERT dbo.Table1(col1, col2, col3) 
SELECT col1, col2, col3 
FROM dbo.tmp_holding_Table1 AS t 
WHERE NOT EXISTS (SELECT 1 FROM dbo.Table1 AS d 
WHERE col1 = t.col1 
AND col2 = t.col2 
AND col3 = t.col3); 

有了這種結合,數據量傳輸到/從您的數據庫被最小化。

0

創建/重建索引時,另一個解決方案可能是IGNORE_DUP_KEY = { ON | OFF }選項。此解決方案將防止插入重複行時發生錯誤。相反,SQL Server將生成警告:Duplicate key was ignored.

CREATE TABLE dbo.MyTable (Col1 INT, Col2 INT, Col3 INT); 
GO 

CREATE UNIQUE INDEX IUN_MyTable_Col1_Col2_Col3 
ON dbo.MyTable (Col1,Col2,Col3) 
WITH (IGNORE_DUP_KEY = ON); 
GO 

INSERT dbo.MyTable (Col1,Col2,Col3) 
VALUES (1,11,111); 
INSERT dbo.MyTable (Col1,Col2,Col3) 
SELECT 1,11,111 UNION ALL 
SELECT 2,22,222 UNION ALL 
SELECT 3,33,333; 
INSERT dbo.MyTable (Col1,Col2,Col3) 
SELECT 2,22,222 UNION ALL 
SELECT 3,33,333; 
GO 
/* 
(1 row(s) affected) 

(2 row(s) affected) 
Duplicate key was ignored. 
*/ 


SELECT * FROM dbo.MyTable; 
/* 
Col1  Col2  Col3 
----------- ----------- ----------- 
1   11   111 
2   22   222 
3   33   333 
*/ 

注:因爲你有一個UNIQUE約束,如果你試圖改變指數期權與ALTER INDEX

ALTER INDEX IUN_MyTable_Col1_Col2_Col3 
ON dbo.MyTable 
REBUILD WITH (IGNORE_DUP_KEY = ON) 

,你會得到以下錯誤:

Msg 1979, Level 16, State 1, Line 1 
Cannot use index option ignore_dup_key to alter index 'IUN_MyTable_Col1_Col2_Col3' as it enforces a primary or unique constraint.` 

所以,如果你選擇此解決方案的選項有:

1)創建另一個UNIQUE索引並刪除UNIQUE約束int(這個選項將需要更多的存儲空間,但將是一個唯一索引/約束始終有效)或者

2)刪除UNIQUE約束並創建一個帶有WITH (IGNORE_DUP_KEY = ON)選項的UNIQUE索引(我不會推薦這最後一個選項) 。