记一次百万数据插入的优化

说明

环境

  • mysql: docker + mysql(8.0.18、8.0.27)
  • jdk8
  • mac 系统

JDBC 方式插入

statement

  • 见 【cc.gegee.study.week7.practice2.Thread1Statement】
  • 19 秒

预处理

  • 见 【cc.gegee.study.week7.practice2.Thread1PreparedStatement】
  • 22 秒

多线程多连接 + statement

  • 见 【cc.gegee.study.week7.practice2.ThreadNStatement】
  • 21 秒

多线程多连接 + 预处理

  • 见 【cc.gegee.study.week7.practice2.ThreadNPreparedStatement】
  • 25 秒

总结

  • 感觉用不用多线程多连接差不多
  • statement 比 预处理方式要快,可能需要多跑几次才能确定

LOAD DATA 方式插入(mysql版本8.0.18)

  • 参考:https://dev.mysql.com/doc/refman/8.0/en/load-data.html
  • 因为我这边用的是 docker,会比本机应用程序会再慢些
  • 需要--local-infile=1 或者 登录后 SET GLOBAL local_infile = 1
  • bin log 打开时测试(其他参数已经优化过了,见下面的优化过程)
mysql -h 127.0.0.1 -uroot -P 3406 --local-infile=1 -p
SET GLOBAL local_infile = 1;
load data local infile '~/Downloads/order.csv' into table test.`order`
    character set utf8mb4 -- 可选,避免中文乱码问题
    fields terminated by ',' -- 字段分隔符,每个字段(列)以什么字符分隔,默认是 \t
    optionally enclosed by '' -- 文本限定符,每个字段被什么字符包围,默认是空字符
    escaped by '/' -- 转义符,默认是 \
    lines terminated by '\n' -- 记录分隔符,如字段本身也含\n,那么应先去除,否则load data
    ( `user_id`, `status`, `money`) -- 每一行文本按顺序对应的表字段,建议不要省略
    ;
  • 输出如下,8.61 sec
Query OK, 1000000 rows affected, 0 warnings (8.61 sec)
Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
  • 关闭 bin log 测试,4.95 sec
Query OK, 1000000 rows affected, 0 warnings (4.95 sec)
Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0

importTable 方式插入(MySQL Shell mysql版本8.0.27)

## 进入 mysql shell 
mysqlsh
## 进入后 session 连接
shell.connect('mysql://root@localhost:3308')
## 然后输入密码进入
## 导出
util.exportTable("test.`order`", "~/Downloads/order.csv")
## 导入
## The parallel table import utility uses LOAD DATA LOCAL INFILE statements to upload data, 
## so the local_infile system variable must be set to ON on the target server. 
## You can do this by issuing the following statement in SQL mode before running the parallel table import utility
\sql SET GLOBAL local_infile = 1;
util.importTable("~/Downloads/order.csv", {"characterSet": "utf8mb4","schema": "test","table": "order"})
  • 输出如下,用时11.5021 sec
Importing from file '/Users/xuqingbin/Downloads/order.csv' to table `test`.`order` in MySQL Server at localhost:3308 using 1 thread
[Worker000] order.csv: Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
100% (19.89 MB / 19.89 MB), 143.13 KB/s
File '/Users/xuqingbin/Downloads/order.csv' (19.89 MB) was imported in 11.5021 sec at 1.73 MB/s
Total rows affected in test.order: Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
  • 关闭 bin log 测试,4.8136 sec
Importing from file '/Users/xuqingbin/Downloads/order.csv' to table `test`.`order` in MySQL Server at localhost:3406 using 1 thread
[Worker000] order.csv: Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
100% (19.89 MB / 19.89 MB), 4.38 MB/s
File '/Users/xuqingbin/Downloads/order.csv' (19.89 MB) was imported in 4.8136 sec at 4.13 MB/s
Total rows affected in test.order: Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0
  • 从日志可以看出importTable的方式可以支持多个线程,应该可以调整,以进一步提高导入速度

优化过程

优化思路可以归结为

  • client层优化
    • Connecting
    • Sending query to server
    • combine many small operations into a single large operation、
    • prepare statement
  • server层优化
  • engine引擎层优化
    • undo log
    • engine层内存缓存
    • 数据磁盘刷新
    • redo log
    • bin log
  • 其他
    • innodb_autoinc_lock_mode
    • max_allowed_packet
    • bulk_insert_buffer_size

以下是具体说明

Inserting indexes

  • 开始主键用的是UUID,执行一次需要200多秒,后来改成主键自增
  • 影响性能的分析与总结
    • 表上如果有索引,插入时会建立索引
    • 聚集索引因为存储按索引排序存储,插入中间索引值时,可能会引起页分裂。所以,如果一定要用UUID,批量插入时,可以先排序在插入。
    • 对于其他索引,可以先删除索引,完成导入后再重新建索引

foreign key

  • SET @@foreign_key_checks=0;
  • 关闭外键检查来加速表导入

UNIQUE

  • SET @@unique_checks=0;
  • InnoDB最后通过缓冲区批量写入二级索引记录保证唯一性
  • 我这里没使用,不涉及

columns set default values

  • Insert values explicitly only when the value to be inserted differs from the default
  • This reduces the parsing that MySQL must do and improves the insert speed
  • 即:当插入的列的值和默认值一样时,可以不指定该列,减少Mysql解析列的时间
  • 即:如果某列的值出现的比较多,甚至可以设置为默认值
  • 我这里表比较简单没有设置默认值

change buffer

  • SET autocommit=0;
  • change buffer会影响磁盘IO次数,关闭自动提交

undo log

  • 没找到可以关闭的设置

redo log

bin log

  • 关闭 bin log
    [mysqld]
    skip-log-bin
  • 查看:show variables like '%log_bin%';

max_allowed_packet

  • 给server端发送的数据包的最大值
  • 我这边 statement 第一次执行时出现超过最大值,后修改
[mysqld]
## 100M
max_allowed_packet=104857600

bulk_insert_buffer_size

[mysqld]
## 100M
bulk_insert_buffer_size=104857600

最后

  • 因为我用的是 docker ,在 JDBC 上使用多线程是否有用以及有多大效果还不确定,不知道容器是否有自己的一套,需要后续使用应用程序起mysql服务方式测试
  • 看mysql官网应该还有针对 InnoDB 的具体优化参数,可以进一步优化,后续有时间再研究
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容