表结构:
CREATE TABLE `t_order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`creator` varchar(16) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'admin' COMMENT '创建人',
`editor` varchar(16) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'admin' COMMENT '修改人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`edit_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`version` bigint(20) NOT NULL DEFAULT '1' COMMENT '版本号',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '软删除标识',
`order_id` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单ID',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额',
`payment_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '支付时间',
`order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态,0:处理中,1:支付成功,2:支付失败',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_order_id` (`order_id`),
KEY `idx_payment_time` (`payment_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='订单表';
存储过程:
CREATE DEFINER=`root`@`%` PROCEDURE `proc_user`(init_num BIGINT, target BIGINT )
BEGIN
DECLARE v_num int(4) DEFAULT 0;
SET autocommit = 0;
while init_num <= target DO
INSERT INTO `t_order` ( `creator`, `editor`, `create_time`, `edit_time`, `version`, `deleted`, `order_id`, `amount`, `payment_time`, `order_status` )
VALUES
( '1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 0, init_num, 1.00, CURRENT_TIMESTAMP, 0 );
SET init_num = init_num + 1;
SET v_num = v_num + 1;
IF v_num >= 100 THEN
SET v_num = 0;
COMMIT;
END IF;
end while;
commit;
END
这里涉及到需要调整mysql的两个参数:
innodb_flush_log_at_trx_commit
sync_binlog
默认情况下
innodb_flush_log_at_trx_commit=1
sync_binlog=1
我们来了解下这两个参数的定义:
innodb_flush_log_at_trx_commit:
提交事务的时候将 redo 日志写入磁盘中,所谓的 redo 日志,就是记录下来你对数据做了什么修改,比如对 “id=10 这行记录修改了 name 字段的值为 xxx”,这就是一个日志。如果我们想要提交一个事务了,此时就会根据一定的策略把 redo 日志从 redo log buffer 里刷入到磁盘文件里去。此时这个策略是通过 innodb_flush_log_at_trx_commit 来配置的,他有几个选项。
值为0 : 提交事务的时候,不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失。
值为1 : 提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了。注意,因为操作系统的“延迟写”特性,此时的刷入只是写到了操作系统的缓冲区中,因此执行同步操作才能保证一定持久化到了硬盘中。
值为2: 提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。
可以看到,只有1才能真正地保证事务的持久性,但是由于刷新操作 fsync() 是阻塞的,直到完成后才返回,我们知道写磁盘的速度是很慢的,因此 MySQL 的性能会明显地下降。如果不在乎事务丢失,0和2能获得更高的性能。
从场景来看,我们需要快速插入,可以将innodb_flush_log_at_trx_commit=2;
sync_binlog
该参数控制着二进制日志写入磁盘的过程。
该参数的有效值为0 、1、N:
0:默认值。事务提交后,将二进制日志从缓冲写入磁盘,但是不进行刷新操作(fsync()),此时只是写入了操作系统缓冲,若操作系统宕机则会丢失部分二进制日志。
1:事务提交后,将二进制文件写入磁盘并立即执行刷新操作,相当于是同步写入磁盘,不经过操作系统的缓存。
N:每写N次操作系统缓冲就执行一次刷新操作。
将这个参数设为1以上的数值会提高数据库的性能,但同时会伴随数据丢失的风险。
二进制日志文件涉及到数据的恢复,以及想在主从之间获得最大的一致性,那么应该将该参数设置为1,但同时也会造成一定的性能损耗。
从场景来看,我们需要快速插入,可以将sync_binlog=500;
测试结果:
参数场景 (100w) | 耗时 (s) |
---|---|
innodb_flush_log_at_trx_commit=1, sync_binlog=1 | 577.491 |
innodb_flush_log_at_trx_commit=2, sync_binlog=500 | 55.534 |