表結(jié)構(gòu):
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 '創(chuàng)建人',
`editor` varchar(16) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'admin' COMMENT '修改人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
`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 '訂單狀態(tài),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
這里涉及到需要調(diào)整mysql的兩個參數(shù):
innodb_flush_log_at_trx_commit
sync_binlog
默認情況下
innodb_flush_log_at_trx_commit=1
sync_binlog=1
我們來了解下這兩個參數(shù)的定義:
innodb_flush_log_at_trx_commit:
提交事務(wù)的時候?qū)?redo 日志寫入磁盤中闺阱,所謂的 redo 日志纲菌,就是記錄下來你對數(shù)據(jù)做了什么修改枉长,比如對 “id=10 這行記錄修改了 name 字段的值為 xxx”,這就是一個日志撒蟀。如果我們想要提交一個事務(wù)了,此時就會根據(jù)一定的策略把 redo 日志從 redo log buffer 里刷入到磁盤文件里去。此時這個策略是通過 innodb_flush_log_at_trx_commit 來配置的捐迫,他有幾個選項。
值為0 : 提交事務(wù)的時候籽腕,不立即把 redo log buffer 里的數(shù)據(jù)刷入磁盤文件的嗡呼,而是依靠 InnoDB 的主線程每秒執(zhí)行一次刷新到磁盤。此時可能你提交事務(wù)了皇耗,結(jié)果 mysql 宕機了南窗,然后此時內(nèi)存里的數(shù)據(jù)全部丟失。
值為1 : 提交事務(wù)的時候郎楼,就必須把 redo log 從內(nèi)存刷入到磁盤文件里去万伤,只要事務(wù)提交成功,那么 redo log 就必然在磁盤里了呜袁。注意敌买,因為操作系統(tǒng)的“延遲寫”特性,此時的刷入只是寫到了操作系統(tǒng)的緩沖區(qū)中阶界,因此執(zhí)行同步操作才能保證一定持久化到了硬盤中虹钮。
值為2: 提交事務(wù)的時候,把 redo 日志寫入磁盤文件對應(yīng)的 os cache 緩存里去荐操,而不是直接進入磁盤文件芜抒,可能 1 秒后才會把 os cache 里的數(shù)據(jù)寫入到磁盤文件里去。
可以看到托启,只有1才能真正地保證事務(wù)的持久性宅倒,但是由于刷新操作 fsync() 是阻塞的,直到完成后才返回屯耸,我們知道寫磁盤的速度是很慢的拐迁,因此 MySQL 的性能會明顯地下降。如果不在乎事務(wù)丟失疗绣,0和2能獲得更高的性能线召。
從場景來看,我們需要快速插入多矮,可以將innodb_flush_log_at_trx_commit=2缓淹;
sync_binlog
該參數(shù)控制著二進制日志寫入磁盤的過程。
該參數(shù)的有效值為0 塔逃、1讯壶、N:
0:默認值。事務(wù)提交后湾盗,將二進制日志從緩沖寫入磁盤伏蚊,但是不進行刷新操作(fsync()),此時只是寫入了操作系統(tǒng)緩沖格粪,若操作系統(tǒng)宕機則會丟失部分二進制日志躏吊。
1:事務(wù)提交后氛改,將二進制文件寫入磁盤并立即執(zhí)行刷新操作,相當于是同步寫入磁盤比伏,不經(jīng)過操作系統(tǒng)的緩存胜卤。
N:每寫N次操作系統(tǒng)緩沖就執(zhí)行一次刷新操作。
將這個參數(shù)設(shè)為1以上的數(shù)值會提高數(shù)據(jù)庫的性能凳怨,但同時會伴隨數(shù)據(jù)丟失的風險瑰艘。
二進制日志文件涉及到數(shù)據(jù)的恢復(fù),以及想在主從之間獲得最大的一致性肤舞,那么應(yīng)該將該參數(shù)設(shè)置為1紫新,但同時也會造成一定的性能損耗。
從場景來看李剖,我們需要快速插入芒率,可以將sync_binlog=500;
測試結(jié)果:
參數(shù)場景 (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 |