我有一张订单表,订单表里面有百万条数据左右。
某一天,发现我们订单表里面缺失一些数据,需要补充这些数据上去。
补充的方法是,从Excel表格里面导入数据到数据库中。一导就是几万条的更新数据。
遇到这种需求,你会怎么做?
背景(创建一张订单表)
订单表,order_id不唯一
因为历史原因,除了ID唯一,其他都不唯一,所以没办法创建唯一索引。
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`order_id` bigint(30) NOT NULL DEFAULT '0' COMMENT '订单id',
`order_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '下单时间',
`finish_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '完成时间',
`goods_id` varchar(255) NOT NULL DEFAULT '' COMMENT '商品id',
`is_import` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否导入数据',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_order_id` (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='广告订单表';
order_id和goods_id属于同一组数据。所以更新条件就是order_id和goods_id
单条更新
因为需要导入的数据一个有几万条,最简单的方式就是直接写几万条update语句。
命名: /root/import.sql
UPDATE order SET finish_time='2025-04-30 22:44:15',is_import=1 WHERE order_id=312752276883 and goods_id='10123600267523';
UPDATE order SET finish_time='2025-04-30 22:25:27',is_import=1 WHERE order_id=3127334304 and goods_id='10114578974526';
UPDATE order SET finish_time='2025-04-30 22:06:19',is_import=1 WHERE order_id=313832333610 and goods_id='10139828706513';
UPDATE order SET finish_time='2025-04-30 20:05:41',is_import=1 WHERE order_id=3131442946843 and goods_id='100121866583';
UPDATE order SET finish_time='2025-04-30 19:48:32',is_import=1 WHERE order_id=313523412157 and goods_id='100108187176';
保存为文件,可以通过链接mysql source执行
mysql -h xxxxxx.com -u root -p
# 密码
# 选择你的数据库
source /root/import.sql
然后你就慢慢等待吧
批量更新
上面那个方式更新,每次会从本地读取一条sql语句到mysql服务器去执行。如果有几万条更新,那么就要读取几万次。几万个网络I/O,mysql服务器也需要解析几万次。
所以这种效率非常的低下。
优化思路就是,让mysql服务器可以批量处理,而不是一条一条处理。把我们需要更新的数据,提前告诉它,让它一次性更新。
这种方式专业名词叫什么我也不知道,好像是MySql Update Join
吧。
原理就是把我们需要更新的数据插入一张临时表里面,然后再使用update join
这样的语句,引用临时表里面的数据,直接就一次批量更新了。
创建一张临时表
-- 创建表(保存需要导入的数据)
CREATE TABLE `import_order` (
`order_id` bigint(20) NOT NULL,
`finish_time` datetime DEFAULT NULL,
`goods_id` bigint(20) DEFAULT NULL
KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 批量插入你要更新的数据
insert into import_order
批量更新语句
-- 更新数据
UPDATE order AS o
INNER JOIN import_order AS i ON o.order_id = i.order_id AND o.goods_id = i.goods_id
SET o.finish_time = i.finish_time, o.is_import = 1
效果和上面的单条更新是一样的。但是效率却是质的提升。
其他批量更新语句参考
UPDATE Per
SET
Per.PersonCityName=Addr.City,
Per.PersonPostCode=Addr.PostCode
FROM Persons Per
INNER JOIN AddressList Addr ON Per.PersonId = Addr.PersonId
UPDATE Persons,AddressList
set
Persons.PersonCityName = AddressList.City,
Persons.PersonPostCode=AddressList.PostCode
where Persons.PersonId = AddressList.PersonId