MySQL INSERT IGNORE 仅跳过PRIMARY KEY或UNIQUE约束冲突,对CHECK、外键、触发器错误无效;PostgreSQL需用ON CONFLICT(column) DO NOTHING精准匹配索引;pandas.to_sql应结合SQL原生忽略机制而非Python层处理。
MySQL INSERT IGNORE 为什么没跳过重复数据
根本原因通常是唯一索引定义和 insert ignore 的作用范围不匹配。它只对违反 primary key 或 unique 约束的行生效,如果冲突来自 check、foreign key 或触发器抛出的错误,insert ignore 完全不拦截。
实操建议:
- 用
SHOW CREATE TABLE <code>table_name确认冲突字段是否真有UNIQUE或PRIMARY KEY约束,而不是仅靠业务逻辑“以为”是唯一 - 避免在复合唯一索引上只提供部分列值插入——缺失列会导致约束无法校验,可能插入重复逻辑但不报错,后续查不到问题根源
-
INSERT IGNORE对自增主键有副作用:即使被忽略,自增 ID 仍会+1,长期运行可能导致 ID 稀疏或溢出
PostgreSQL 怎么等价实现“忽略重复”
PostgreSQL 没有 INSERT IGNORE,必须用 ON CONFLICT 子句,语法更明确但也更容易写错目标索引。
常见错误现象:执行后仍报 duplicate key value violates unique constraint,说明 ON CONFLICT 没命中对应索引。
实操建议:
- 显式写出冲突目标:
ON CONFLICT (<code>column_name) DO NOTHING,不能只写ON CONFLICT DO NOTHING(8.0+ 要求指定索引或列) - 复合唯一索引需列出全部列,顺序必须和索引定义一致,例如索引是
CREATE UNIQUE INDEX idx_user_email ON users (org_id, email),就得写ON CONFLICT (org_id, email) DO NOTHING - 若表有多个唯一约束,但只想忽略其中一种冲突,必须精准指定列,否则可能意外吞掉其他类型错误
Python pandas.to_sql 如何安全跳过重复记录
to_sql 的 if_exists='append' 默认遇到唯一冲突就直接抛 IntegrityError,不提供内置“忽略”开关。
性能与兼容性影响明显:逐条用 try/except 插入在万级数据下极慢;而先查后插(SELECT ... WHERE EXISTS)在高并发时存在竞态漏洞。
实操建议:
- 用 SQLAlchemy 的
on_conflict_do_nothing(PostgreSQL)或 MySQL 的INSERT IGNORE配合method='multi'批量提交,避免 Python 层循环 - 确保 DataFrame 列名和数据库字段名严格一致,大小写敏感;列顺序错位可能导致唯一索引判断失效
- 别依赖
dtype参数强行映射为String(255)却忽略数据库实际索引长度——比如 MySQL 对VARCHAR(50)建了唯一索引,但传入 51 字符会被截断再比较,行为不可控
什么时候不该用“忽略重复”,而是该改数据或逻辑
线上批量导入频繁触发唯一冲突,大概率不是 SQL 选项问题,而是上游数据治理失控或业务规则模糊。
容易被忽略的点:
- 时间戳精度不一致:Python 生成的
datetime默认微秒级,数据库字段却是DATETIME(0),入库时被截断导致多条记录“看起来”重复 - 空字符串
''和NULL在唯一索引中是否等价?MySQL 5.7+ 中UNIQUE允许多个NULL,但''是真实值,混用会误判 - 忽略后不记录日志——下次排查数据缺失时,没人知道哪几行被静默丢弃了
真正麻烦的从来不是怎么跳过,而是跳过之后没人再核对那几行到底该不该存在。

















