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

本文关键字:最佳 方法 添加 数据库 | 更新日期: 2023-09-27 18:37:14

我有一个包含三列的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:HashSet<T>提供了一种在将它们发送到数据库之前避免重复的快速方法。你应该实现一个更好的GetHashCode,例如,使用Skeet的实现,来自被覆盖的System.Object.GetHashCode的最佳算法是什么?

但是有一个问题:如果表已经包含可能与您的 CSV 重复的数据怎么办?您必须先将整个表复制下来,才能使简单的HashSet真正起作用。你可以这样做,但为了解决这个问题,我可能会将选项 1 与一个临时表和一个插入语句配对,例如跳过/忽略插入上的重复行:

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

通过这种组合,可以最大限度地减少传入/传出数据库的数据量。

另一种解决方案可能是创建/重建索引时的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
*/

注: 因为如果您尝试使用 ALTER INDEX 更改索引选项,则存在 UNIQUE 约束

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 约束(此选项将需要更多的存储空间,但将始终处于活动状态的唯一索引/约束)或

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