主键重复记录绕过下一个插入

时间:2010-01-25 22:47:48

标签: sql-server primary-key

奇怪的问题。我在表中插入10,000条记录,主键不是标识字段。所以当插入所有10,000,如果有些是重复的,有没有办法跳转到sql server插入中的下一条记录,并确保非重复进入?我真的不在乎没有插入重复项。

4 个答案:

答案 0 :(得分:8)

使用“忽略重复键”选项。

最简单的方法是删除SQL Server Management Studio中的主键。

然后创建一个类型为“Index”的新索引,将Is Unique设置为“Yes”,并将“Ignore Duplicate Keys”设置为“Yes”。然后插入您的记录。除了重复之外,它会将它们全部插入。完成后,您可以删除此索引,然后重新创建主键。

如果需要TSQL方法,请参阅CREATE INDEX调用中的IGNORE_DUP_KEY选项:

CREATE INDEX (Transact-SQL)

编辑:

另一种方法是在源表和要插入的记录之间使用LEFT JOIN,以及GROUP BY子句,只插入源中不存在的记录。 GROUP BY将消除新记录中的重复项。

答案 1 :(得分:5)

您需要定义主键以忽略重复项:

CREATE TABLE [dbo].[t2](
      [n] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
      [n] ASC
)WITH (IGNORE_DUP_KEY = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

使用此选项可能会影响性能:

如果您的数据具有较小百分比的重复项,那么IGNORE_DUP_KEY可能会加快您的插入速度。对于大量重复项,IGNORE_DUP_KEY可能会显着降低它们的速度。我设置了两个表,删除了所有不相关的细节,如下所示:

CREATE TABLE t1(n INT NOT NULL PRIMARY KEY)
GO
CREATE TABLE [dbo].[t2](
      [n] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
      [n] ASC
)WITH (IGNORE_DUP_KEY = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

如果传入的数据没有重复,则两个插入的性能始终相同:

INSERT t1(n)
SELECT n FROM dbo.Numbers

INSERT t2(n)
SELECT n FROM dbo.Numbers

(请注意,dbo。数字有100万行。)当然,我总是在测试之间截断两个表。

如果传入的数据有1%的重复数据,那么IGNORE_DUP_KEY的插入执行速度大约提高了约5%:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers WHERE n <10000
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers WHERE n <10000

另一方面,如果传入数据具有100%的重复数据,则IGNORE_DUP_KEY的插入执行速度始终至少慢300%,对于大量的200万行都是如此:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers

以及一组较小的200K行:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers WHERE n<100000
UNION ALL
SELECT n FROM dbo.Numbers WHERE n<100000
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers WHERE n<100000
UNION ALL
SELECT n FROM dbo.Numbers WHERE n<100000 

总的来说,我决定不在我的特定情况下使用IGNORE_DUP_KEY。我认为,少量重复项的小额节省并不能证明大量重复数据会导致性能大幅下降的风险。

答案 2 :(得分:2)

此示例查询跳过PK1的重复行:

INSERT INTO Dest (PK1, Field2)
SELECT s.PK1, s.F2
FROM Source s
WHERE
(
    SELECT TOP 1 d.PK1
    FROM Dest d
    WHERE d.PK1 = s.PK1
) IS NULL

答案 3 :(得分:0)

有几种方法让人想起,因为我不知道你用什么机制来插入。

1)将所有记录批量加载到新的空表中,然后从该临时表中运行INSERT到实际表中,其中主表中尚不存在该记录。 e.g。

INSERT MyRealTable (PKField, Field1)
SELECT x.PKField, x.Field1
FROM MyStagingTable x
    LEFT JOIN MyRealTable r ON x.PKField = r.PKField
WHERE r.PKField IS NULL

2)将每个插入包装在TRY...CATCH块中,以便在发生任何情况时吞下PK约束错误(如果您使用的是SQL 2005或更高版本)。