ignore_dup_key = on 仅在索引或主键约束定义时生效,非 insert 选项;设为 on 后批量插入重复键行会被静默跳过,不报错但难审计,且不支持 output,推荐用 merge 或 if not exists 替代。

IGNORE_DUP_KEY = ON 不能直接用于 INSERT 语句,它只在索引(含主键约束)定义时生效,且仅对非聚集唯一索引或主键约束有效;误设为 ON 可能掩盖数据一致性问题,需谨慎评估。
IGNORE_DUP_KEY 是索引属性,不是 INSERT 选项
很多人搜到“INSERT IGNORE”就以为 SQL Server 支持类似 MySQL 的语法,其实完全不成立。IGNORE_DUP_KEY 是 CREATE INDEX 或 ALTER TABLE ... ADD CONSTRAINT 时的可选参数,作用对象是索引本身,而非某次插入操作。它不会改变 SQL 语义,也不会让 INSERT 语句多出一个“忽略”关键字。
- 主键约束底层就是唯一聚集索引,所以给主键加
IGNORE_DUP_KEY = ON是可行的 - 但普通
PRIMARY KEY约束默认创建时IGNORE_DUP_KEY = OFF,必须显式修改 - 一旦设为
ON,所有后续对该索引的INSERT(包括批量、SSIS、应用层直连)都会跳过重复键行,不报错也不回滚整批
如何安全启用 IGNORE_DUP_KEY
不能直接 ALTER 主键约束,得先删再重建,或改用唯一非聚集索引替代主键(不推荐)。更稳妥的做法是:
- 确认表无并发写入压力——
IGNORE_DUP_KEY = ON下冲突行静默丢弃,无法审计哪些被跳过了 - 用
ALTER TABLE ... DROP CONSTRAINT删除原主键约束 - 用
ALTER TABLE ... ADD CONSTRAINT pk_name PRIMARY KEY (...) WITH (IGNORE_DUP_KEY = ON)重建 - 测试时务必用含重复值的批量
INSERT验证:成功行数 ≠ 输入行数,且无错误抛出
示例语句:
ALTER TABLE dbo.Users DROP CONSTRAINT PK_Users;<br>ALTER TABLE dbo.Users ADD CONSTRAINT PK_Users PRIMARY KEY (ID) WITH (IGNORE_DUP_KEY = ON);
MERGE 和 IF NOT EXISTS 更可控,但性能略低
如果只是偶尔插入几条,或需要知道“哪些没插进去”,MERGE 或 IF NOT EXISTS 是更透明的选择:
-
MERGE能在一个语句里完成“存在则跳过,不存在则插入”,逻辑清晰,支持输出受影响行 -
IF NOT EXISTS (SELECT 1 FROM t WHERE key = @val)写法简单,但有竞态风险(两次查询间可能被其他事务插入) - 两者都会触发索引查找,而
IGNORE_DUP_KEY = ON是引擎级跳过,批量插入时吞吐更高
典型 MERGE 片段:
MERGE dbo.Users AS t<br>USING (VALUES (@id, @name)) AS s(id, name) ON t.ID = s.id<br>WHEN NOT MATCHED THEN INSERT (ID, Name) VALUES (s.id, s.name);
容易被忽略的副作用
IGNORE_DUP_KEY = ON 看似省事,但埋了几个硬伤:
- SQL Server 日志里不会记录被忽略的行,出问题后难以追溯“为什么某些数据没进来”
- 它对所有客户端一视同仁——应用层以为插入成功了,其实部分数据被静默吞掉
- 在 Always On 可用性组中,
IGNORE_DUP_KEY行为一致,但 secondary 副本同步时若遇到本地已存在冲突键,同样跳过,可能造成主备数据逻辑不一致(虽物理一致) - 不能和
OUTPUT子句配合使用——你没法拿到被跳过的那些键值做后续处理
真正需要“忽略重复”的场景,往往意味着上游数据源质量不可控,这时候与其依赖数据库层兜底,不如在 ETL 或应用层加去重逻辑,把“是否重复”变成可观察、可干预的步骤。











