C# 避免在数据库中添加重复项的最佳方法

C# 避免在数据库中添加重复项的最佳方法,c#,sql-server,hashset,C#,Sql Server,Hashset,我有一个包含三列的SQL Server表: 表1 col1 int col2 int col3 string 我为所有三列(col1、col2、col3) 现在,我有一个.csv文件,我想在这个表中添加记录,*.csv文件可以有重复的记录 我已经在上面的场景中搜索了各种避免重复的选项。下面是三个对我很有效的选项。请看一看,并就每种方法的优缺点提出一些想法,以便我可以选择最好的方法 选项#1: 首先避免重复,即从csv文件向列表中添加对象时。我为此使用了HashSet,并覆盖了以下类型T的方法:

我有一个包含三列的SQL Server表:

表1

col1 int
col2 int
col3 string
我为所有三列
(col1、col2、col3)

现在,我有一个.csv文件,我想在这个表中添加记录,*.csv文件可以有重复的记录

我已经在上面的场景中搜索了各种避免重复的选项。下面是三个对我很有效的选项。请看一看,并就每种方法的优缺点提出一些想法,以便我可以选择最好的方法

选项#1:

首先避免重复,即从csv文件向列表中添加对象时。我为此使用了
HashSet
,并覆盖了以下类型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

具有
列表
而不是
哈希集

将所有对象添加到
列表后删除重复项

虽然我没有比较它们的运行时间,但我更喜欢选项#1,因为我将删除重复项作为第一步-因此只需要按照需要继续

请分享你的观点,这样我可以选择最好的


非常感谢

我喜欢选项1:
HashSet
提供了一种在发送到数据库之前避免重复的快速方法。您应该实现更好的
GetHashCode
,例如,从

但有一个问题:如果表中已经包含可能与CSV重复的数据,该怎么办?为了使一个简单的
HashSet
真正起作用,您必须首先复制整个表。您可以这样做,但要解决这个问题,我可能会将选项1与临时表和insert语句配对,如:


通过这种组合,可以最大限度地减少从数据库传输到数据库的数据量。

另一种解决方案是在创建/重建索引时使用
IGNORE\u DUP\u KEY={ON | OFF}
选项。此解决方案将防止插入重复行时出错。相反,SQL Server将生成警告:
重复密钥被忽略。

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
*/
注意:因为如果您尝试使用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) 创建另一个唯一索引并删除唯一约束(此选项将需要更多存储空间,但唯一索引/约束将始终处于活动状态)或


2) 删除唯一约束并使用(IGNORE_DUP_KEY=ON)
选项创建一个唯一索引(我不建议使用最后一个选项)。

从csv获取数据并将其批量插入没有唯一约束的临时表不是更有效吗,使用sql删除重复项,然后将没有重复项的数据移动到实际的最终表中?如果使用选项1,我可能会将
GetHashCode
更改为将属性乘以素数,就像在这个废弃选项1中一样-使用哈希代码不能保证唯一性。@DStanley哈希代码本身不能保证唯一性,但是,如上所述使用的
HashSet
,正是他想要做的。@iniki您考虑过使用SSIS吗?在数据流任务中,您可以将错误行重定向到某些输出或忽略它们。这样,只会插入第一个唯一的行。
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
*/
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.`