数据库技巧:INSERT IGNORE的高效插入策略

引用

作为一个软件开发人员,特别是要与数据库打交道的靓仔,你就不可避免的要遇到数据重复插入的问题,如果你没有唯一键或者主键之类的,那无话可说,但是你很好的设计了数据库唯一索引和主键,哪当我们插入数据的时候,你就必须做好去重处理。

代码里面有很多方法,预检查,分布式锁等等;但是有一些场景,我们要快速迁移大量的数据,有的时候会分批次多阶段的处理,这个时候如果都来做预检就很耗时,本文将介绍INSERT IGNORE的用法,特别适合解决这一问题。

一、 基本语法

INSERT IGNORE 是 MySQL 中一个非常实用的语句,用于在插入数据时避免重复键错误(如主键冲突或唯一索引冲突)。它可以帮助你优雅地处理数据重复问题,而不会抛出错误。

INSERT IGNORE 的基本语法与普通的 INSERT 语句非常相似,只是在 INSERT 关键字后面加上了 IGNORE 关键字。以下是常见的语法形式:

  • 插入单行数据
sql 复制代码
INSERT IGNORE INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN);
  • 插入多行数据
sql 复制代码
INSERT IGNORE INTO table_name (column1, column2, ..., columnN)
VALUES 
    (value1a, value2a, ..., valueNa),
    (value1b, value2b, ..., valueNb),
    ...
    (value1n, value2n, ..., valueNn);
  • 插入查询结果
sql 复制代码
INSERT IGNORE INTO table_name (column1, column2, ..., columnN)
SELECT column1, column2, ..., columnN
FROM another_table
WHERE condition;

二、 工作原理

INSERT IGNORE 的主要功能是忽略插入操作中可能导致重复键错误的行。以下是其工作原理的详细说明:

2.1 忽略重复键错误

当尝试插入的数据违反了表的唯一性约束(如主键或唯一索引)时,INSERT IGNORE 会自动忽略该插入操作,不会抛出错误。例如:

假设有一个表 users,结构如下:

sql 复制代码
CREATE TABLE `user_info` (
  `id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id',
  `risk_score` int NOT NULL DEFAULT '0' COMMENT '风险评分 0-100 (不可超出该范围)',
  `risk_level` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-安全 1-低风险 2-中风险 3-高风险',
  `register_time` datetime NOT NULL COMMENT '注册时间',
  `created` datetime NOT NULL COMMENT '创建时间(北京时间)',
  `updated` datetime DEFAULT NULL COMMENT '修改时间(北京时间)',
  `creator` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人',
  `updater` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`id`),
  KEY `idx_updated` (`updated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户安全信息表';

如果尝试插入以下SQL:

SQL 复制代码
INSERT IGNORE INTO `user_info`
(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) 
VALUES 
('11-000034639cc4408aba88358e73d48517', 10, 0, '2023-02-28 20:28:58', '2025-03-21 17:02:21', '2025-03-21 17:02:36', 'admin', 'admin');

通过下图可以看到,当11-000034639cc4408aba88358e73d48517已经存在的时候,MySQL 会忽略该插入操作,不会报错。

注意:这里只是根据唯一键和主键去判断是否存在,至于其它的值是否发生变化不会拿来判断。

2.2 返回值

INSERT IGNORE 的返回值是一个整数,表示插入操作的结果:

  • 返回值为 1:表示插入成功。

  • 返回值为 0:表示插入操作被忽略(因为数据重复)。

  • 返回值为 n :表示成功插入了 n 行数据(在插入多行时)。

2.3 扩展:查看警告信息

即使 INSERT IGNORE 忽略了插入操作,MySQL 仍然会生成一个警告(Duplicate entry)。你可以通过以下命令查看警告信息:

sql 复制代码
SHOW WARNINGS;

例如:

sql 复制代码
INSERT IGNORE INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) VALUES ('11-000034639cc4408aba88358e73d48517', 10, 0, '2023-02-28 20:28:58', '2025-03-21 17:02:21', '2025-03-21 17:02:36', 'admin', 'admin');

SHOW WARNINGS;

输出结果如下:

三、 使用场景

INSERT IGNORE 非常适用于以下场景:

3.1 避免重复数据插入

当你需要插入大量数据,但不确定某些数据是否已经存在时,INSERT IGNORE 可以帮助你避免重复插入,同时不会抛出错误。例如:

sql 复制代码
INSERT IGNORE INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) VALUES 
('11-000034639cc4408aba88358e73d48517', 10, 0, '2023-02-28 20:28:58', '2025-03-21 17:02:21', '2025-03-21 17:02:36', 'admin', 'admin'),
('11-000034639cc4408aba88358e73d48517', 10, 0, '2023-02-28 20:28:58', '2025-03-21 17:02:21', '2025-03-21 17:02:36', 'admin', 'admin');

执行结果:

3.2 数据导入

在从其他数据源导入数据时,INSERT IGNORE 可以确保不会因为重复数据而导致插入失败。例如:

SQL 复制代码
INSERT IGNORE INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) 
SELECT `id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater` FROM asrc_user_info;

执行结果:

3.3 日志记录

在记录日志或事件时,INSERT IGNORE 可以确保不会因为重复记录而导致错误。

这种场景主要在于一些日志重复上报的情况。

四、注意事项

虽然 INSERT IGNORE 非常方便,但在使用时还是要慎重,需要注意以下几点:

4.1 不仅限于重复键错误

INSERT IGNORE 不仅会忽略重复键错误,还会忽略其他类型的错误(如外键约束错误)。因此,如果你只想忽略重复键错误,而希望其他错误抛出异常,可以使用 ON DUPLICATE KEY UPDATE 或其他机制。

4.2 性能影响

虽然 INSERT IGNORE 的性能通常较高,但在插入大量数据时,仍然需要注意性能问题。如果表中存在大量唯一索引,可能会导致插入操作变慢。在这种情况下,可以考虑批量插入或优化表结构。

4.3 注意:重要业务数据不能丢

因为是根据唯一键这些进行去重,有一些场景可能是插入或者更新的重要数据,不能使用这个语句,切记。

五、与INSERT插入的区别

看到这里对他们之间的区别相信在脑海中已经有一个概念了,下面我将用一个图更加清晰的表示两者的区别:

从上图可以看出,他们两个实际都是进行了约束检查的,只是一个返回错误信息,停止语句的执行,一个生成告警信息,跳过当前行继续执行。

六、总结

INSERT IGNORE就像一个温柔的数据库管理员,遇到重复数据时不会大喊大叫抛出错误,而是默默跳过,继续处理下一条。

无论是批量导入数据、避免重复插入,还是处理日志重复上报,它都能轻松搞定。

不过,它也有小脾气,比如会忽略所有错误(不只是重复键),所以用的时候得小心。

总之,INSERT IGNORE 是数据库操作中的"温柔一刀",帮你优雅地解决问题,但别忘了检查它的"副作用"哦!

希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。

同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。

感谢您的支持和理解!

相关推荐
不光头强2 小时前
spring cloud知识总结
后端·spring·spring cloud
Mike117.2 小时前
GBase 8a 日期边界写法和时间窗口取数偏差
数据库
SPC的存折3 小时前
1、Redis数据库基础
linux·运维·服务器·数据库·redis·缓存
GetcharZp5 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多5 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
小小李程序员6 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai
MatrixOrigin7 小时前
数据库没有死,只是范式变了
数据库·oracle
GreenTea8 小时前
AI Agent 评测的下半场:从方法论到落地实践
前端·人工智能·后端