MySQL Shell import_table数据导入的实现


Posted in MySQL onAugust 07, 2021

1. import_table介绍

上期技术分享我们介绍了MySQL Load Data的4种常用的方法将文本数据导入到MySQL,这一期我们继续介绍另一款更加高效的数据导入工具,MySQL Shell 工具集中的import_table,该工具的全称是Parallel Table Import Utility,顾名思义,支持并发数据导入,该工具在MySQL Shell 8.0.23版本后,功能更加完善, 以下列举该工具的核心功能

  • 基本覆盖了MySQL Data Load的所有功能,可以作为替代品使用
  • 默认支持并发导入(支持自定义chunk大小)
  • 支持通配符匹配多个文件同时导入到一张表(非常适用于相同结构数据汇总到一张表)
  • 支持限速(对带宽使用有要求的场景,非常合适)
  • 支持对压缩文件处理
  • 支持导入到5.7及以上MySQL

2. Load Data 与 import table功能示例

该部分针对import table和Load Data相同的功能做命令示例演示,我们依旧以导入employees表的示例数据为例,演示MySQL Load Data的综合场景

  • 数据自定义顺序导入
  • 数据函数处理
  • 自定义数据取值
## 示例数据如下
[root@10-186-61-162 tmp]# cat employees_01.csv
"10001","1953-09-02","Georgi","Facello","M","1986-06-26"
"10003","1959-12-03","Parto","Bamford","M","1986-08-28"
"10002","1964-06-02","Bezalel","Simmel","F","1985-11-21"
"10004","1954-05-01","Chirstian","Koblick","M","1986-12-01"
"10005","1955-01-21","Kyoichi","Maliniak","M","1989-09-12"
"10006","1953-04-20","Anneke","Preusig","F","1989-06-02"
"10007","1957-05-23","Tzvetan","Zielinski","F","1989-02-10"
"10008","1958-02-19","Saniya","Kalloufi","M","1994-09-15"
"10009","1952-04-19","Sumant","Peac","F","1985-02-18"
"10010","1963-06-01","Duangkaew","Piveteau","F","1989-08-24"

## 示例表结构
 10.186.61.162:3306  employees  SQL > desc emp;
+-------------+---------------+------+-----+---------+-------+
| Field       | Type          | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| emp_no      | int           | NO   | PRI | NULL    |       |
| birth_date  | date          | NO   |     | NULL    |       |
| first_name  | varchar(14)   | NO   |     | NULL    |       |
| last_name   | varchar(16)   | NO   |     | NULL    |       |
| full_name   | varchar(64)   | YES  |     | NULL    |       |  -- 表新增字段,导出数据文件中不存在
| gender      | enum('M','F') | NO   |     | NULL    |       |
| hire_date   | date          | NO   |     | NULL    |       |
| modify_date | datetime      | YES  |     | NULL    |       |  -- 表新增字段,导出数据文件中不存在
| delete_flag | varchar(1)    | YES  |     | NULL    |       |  -- 表新增字段,导出数据文件中不存在
+-------------+---------------+------+-----+---------+-------+

2.1 用Load Data方式导入数据

具体参数含义不做说明,需要了解语法规则及含义可查看系列上一篇文章<MySQL Load Data的多种用法>

load data infile '/data/mysql/3306/tmp/employees_01.csv'
into table employees.emp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
(@C1,@C2,@C3,@C4,@C5,@C6)
set emp_no=@C1,
    birth_date=@C2,
    first_name=upper(@C3),
    last_name=lower(@C4),
    full_name=concat(first_name,' ',last_name),
    gender=@C5,
    hire_date=@C6 ,
    modify_date=now(),
    delete_flag=if(hire_date<'1988-01-01','Y','N');

MySQL Shell import_table数据导入的实现

2.2 用import_table方式导入数据

util.import_table(
    [
        "/data/mysql/3306/tmp/employees_01.csv",
    ],
    {
        "schema": "employees", 
        "table": "emp",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "columns": [1,2,3,4,5,6],                   ## 文件中多少个列就用多少个序号标识就行
        "decodeColumns": {
            "emp_no":       "@1",                   ## 对应文件中的第1列
            "birth_date":   "@2",                   ## 对应文件中的第2个列
            "first_name":   "upper(@3)",            ## 对应文件中的第3个列,并做转为大写的处理
            "last_name":    "lower(@4)",            ## 对应文件中的第4个列,并做转为大写的处理
            "full_name":    "concat(@3,' ',@4)",    ## 将文件中的第3,4列合并成一列生成表中字段值
            "gender":       "@5",                   ## 对应文件中的第5个列
            "hire_date":    "@6",                   ## 对应文件中的第6个列
            "modify_date":  "now()",                ## 用函数生成表中字段值
            "delete_flag":  "if(@6<'1988-01-01','Y','N')"  ## 基于文件中第6列做逻辑判断,生成表中对应字段值
        }
    })

MySQL Shell import_table数据导入的实现

MySQL Shell import_table数据导入的实现

3. import_table特定功能

3.1 多文件导入(模糊匹配)

## 在导入前我生成好了3分单独的employees文件,导出的结构一致
[root@10-186-61-162 tmp]# ls -lh
总用量 1.9G
-rw-r----- 1 mysql mysql  579 3月  24 19:07 employees_01.csv
-rw-r----- 1 mysql mysql  584 3月  24 18:48 employees_02.csv
-rw-r----- 1 mysql mysql  576 3月  24 18:48 employees_03.csv
-rw-r----- 1 mysql mysql 1.9G 3月  26 17:15 sbtest1.csv

## 导入命令,其中对对文件用employees_*做模糊匹配
util.import_table(
    [
        "/data/mysql/3306/tmp/employees_*",
    ],
    {
        "schema": "employees", 
        "table": "emp",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "columns": [1,2,3,4,5,6],                   ## 文件中多少个列就用多少个序号标识就行
        "decodeColumns": {
            "emp_no":       "@1",                   ## 对应文件中的第1列
            "birth_date":   "@2",                   ## 对应文件中的第2个列
            "first_name":   "upper(@3)",            ## 对应文件中的第3个列,并做转为大写的处理
            "last_name":    "lower(@4)",            ## 对应文件中的第4个列,并做转为大写的处理
            "full_name":    "concat(@3,' ',@4)",    ## 将文件中的第3,4列合并成一列生成表中字段值
            "gender":       "@5",                   ## 对应文件中的第5个列
            "hire_date":    "@6",                   ## 对应文件中的第6个列
            "modify_date":  "now()",                ## 用函数生成表中字段值
            "delete_flag":  "if(@6<'1988-01-01','Y','N')"  ## 基于文件中第6列做逻辑判断,生成表中对应字段值
        }
    })
    
## 导入命令,其中对要导入的文件均明确指定其路径
util.import_table(
    [
        "/data/mysql/3306/tmp/employees_01.csv",
        "/data/mysql/3306/tmp/employees_02.csv",
        "/data/mysql/3306/tmp/employees_03.csv"
    ],
    {
        "schema": "employees", 
        "table": "emp",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "columns": [1,2,3,4,5,6],                   ## 文件中多少个列就用多少个序号标识就行
        "decodeColumns": {
            "emp_no":       "@1",                   ## 对应文件中的第1列
            "birth_date":   "@2",                   ## 对应文件中的第2个列
            "first_name":   "upper(@3)",            ## 对应文件中的第3个列,并做转为大写的处理
            "last_name":    "lower(@4)",            ## 对应文件中的第4个列,并做转为大写的处理
            "full_name":    "concat(@3,' ',@4)",    ## 将文件中的第3,4列合并成一列生成表中字段值
            "gender":       "@5",                   ## 对应文件中的第5个列
            "hire_date":    "@6",                   ## 对应文件中的第6个列
            "modify_date":  "now()",                ## 用函数生成表中字段值
            "delete_flag":  "if(@6<'1988-01-01','Y','N')"  ## 基于文件中第6列做逻辑判断,生成表中对应字段值
        }
    })

MySQL Shell import_table数据导入的实现

MySQL Shell import_table数据导入的实现

3.2 并发导入

在实验并发导入前我们创建一张1000W的sbtest1表(大约2G数据),做并发模拟,import_table用threads参数作为并发配置, 默认为8个并发.

## 导出测试需要的sbtest1数据
[root@10-186-61-162 tmp]# ls -lh
总用量 1.9G
-rw-r----- 1 mysql mysql  579 3月  24 19:07 employees_01.csv
-rw-r----- 1 mysql mysql  584 3月  24 18:48 employees_02.csv
-rw-r----- 1 mysql mysql  576 3月  24 18:48 employees_03.csv
-rw-r----- 1 mysql mysql 1.9G 3月  26 17:15 sbtest1.csv

## 开启threads为8个并发
util.import_table(
    [
        "/data/mysql/3306/tmp/sbtest1.csv",
    ],
    {
        "schema": "demo", 
        "table": "sbtest1",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "threads": "8"
    })

MySQL Shell import_table数据导入的实现

MySQL Shell import_table数据导入的实现

3.3 导入速率控制

可以通过maxRatethreads来控制每个并发线程的导入数据,如,当前配置线程为4个,每个线程的速率为2M/s,则最高不会超过8M/s

util.import_table(
    [
        "/data/mysql/3306/tmp/sbtest1.csv",
    ],
    {
        "schema": "demo", 
        "table": "sbtest1",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "threads": "4",
        "maxRate": "2M"
    })

MySQL Shell import_table数据导入的实现

3.4 自定义chunk大小

默认的chunk大小为50M,我们可以调整chunk的大小,减少事务大小,如我们将chunk大小调整为1M,则每个线程每次导入的数据量也相应减少

util.import_table(
    [
        "/data/mysql/3306/tmp/sbtest1.csv",
    ],
    {
        "schema": "demo", 
        "table": "sbtest1",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4",
        "threads": "4",
        "bytesPerChunk": "1M",
        "maxRate": "2M"
    })

MySQL Shell import_table数据导入的实现

4. Load Data vs import_table性能对比

  • 使用相同库表
  • 不对数据做特殊处理,原样导入
  • 不修改参数默认值,只指定必备参数
-- Load Data语句
load data infile '/data/mysql/3306/tmp/sbtest1.csv'
into table demo.sbtest1
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'

-- import_table语句
util.import_table(
    [
        "/data/mysql/3306/tmp/sbtest1.csv",
    ],
    {
        "schema": "demo", 
        "table": "sbtest1",
        "dialect": "csv-unix",
        "skipRows": 0,
        "showProgress": True,
        "characterSet": "utf8mb4"
    })

MySQL Shell import_table数据导入的实现

MySQL Shell import_table数据导入的实现

可以看到,Load Data耗时约5分钟,而import_table则只要不到一半的时间即可完成数据导入,效率高一倍以上(虚拟机环境磁盘IO能力有限情况下)

5. 技术总结

  • import_table包含了Load Data几乎所有的功能
  • import_table导入的效率比Load Data更高
  • import_table支持对导入速度,并发以及每次导入的数据大小做精细控制
  • import_table的导入进度报告更加详细,便于排错及时间评估,包括
    • 导入速度
    • 导入总耗时
    • 每批次导入的数据量,是否存在Warning等等
    • 导入最终的汇总报告

到此这篇关于MySQL import_table数据导入的实现的文章就介绍到这了,更多相关MySQL import_table数据导入内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL之PXC集群搭建的方法步骤
May 25 MySQL
Mysql 设置boolean类型的操作
Jun 04 MySQL
详细谈谈MYSQL中的COLLATE是什么
Jun 11 MySQL
浅谈MySQL user权限表
Jun 18 MySQL
Mysql数据库按时间点恢复实战记录
Jun 30 MySQL
MySQL系列之八 MySQL服务器变量
Jul 02 MySQL
MySQL修炼之联结与集合浅析
Oct 05 MySQL
MySQL悲观锁与乐观锁的实现方案
Nov 02 MySQL
MySQL学习之基础操作总结
Mar 19 MySQL
Linux系统下MySQL配置主从分离的步骤
Mar 21 MySQL
MySQL学习必备条件查询数据
Mar 25 MySQL
MySQL 原理与优化之Limit 查询优化
Aug 14 MySQL
MySQL配置主从服务器(一主多从)
SQL实现LeetCode(180.连续的数字)
Aug 04 #MySQL
Mysql中where与on的区别及何时使用详析
Aug 04 #MySQL
SQL实现LeetCode(178.分数排行)
Aug 04 #MySQL
SQL实现LeetCode(177.第N高薪水)
Aug 04 #MySQL
MySQL千万级数据表的优化实战记录
Aug 04 #MySQL
SQL实现LeetCode(176.第二高薪水)
Aug 04 #MySQL
You might like
php中删除字符串中最先出现某个字符的实现代码
2013/02/03 PHP
php文件夹的创建与删除方法
2015/01/24 PHP
CodeIgniter实现从网站抓取图片并自动下载到文件夹里的方法
2015/06/17 PHP
ThinkPHP3.2.2实现持久登录(记住我)功能的方法
2016/05/16 PHP
如何运行/调试你的PHP代码
2020/10/23 PHP
脚本收藏iframe
2006/07/21 Javascript
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
jQuery 学习第五课 Ajax 使用说明
2010/05/17 Javascript
event.X和event.clientX的区别分析
2011/10/06 Javascript
js三种排序算法分享
2012/08/16 Javascript
关于eval 与new Function 到底该选哪个?
2013/04/17 Javascript
javascritp添加url参数将参数加入到url中
2014/09/25 Javascript
javascript中Function类型详解
2015/04/28 Javascript
模板视图和AngularJS之间冲突的解决方法
2016/11/22 Javascript
flag和jq on 的绑定多个对象和方法(必看)
2017/02/27 Javascript
VUEJS 2.0 子组件访问/调用父组件的实例
2018/02/10 Javascript
解决vue v-for 遍历循环时key值报错的问题
2018/09/06 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
2019/11/14 Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
2020/07/19 Javascript
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
[58:35]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.22
2019/09/05 DOTA
Python多线程编程(一):threading模块综述
2015/04/05 Python
Python日期的加减等操作的示例
2017/08/15 Python
Python列表推导式与生成器用法分析
2018/08/02 Python
numpy数组之存取文件的实现示例
2019/05/24 Python
Python中 CSV格式清洗与转换的实例代码
2019/08/29 Python
学python爬虫能做什么
2020/07/29 Python
numpy实现RNN原理实现
2021/03/02 Python
Hawes & Curtis澳大利亚官网:英国经典服饰品牌
2018/10/29 全球购物
香港最大的洋酒零售连锁店:屈臣氏酒窖(Watson’s Wine)
2018/12/10 全球购物
财务统计员岗位职责
2015/04/14 职场文书
超强台风观后感
2015/06/09 职场文书
施工安全协议书
2016/03/22 职场文书
《鲁班学艺》读后感3篇
2019/11/27 职场文书
800字作文之大雪
2019/12/04 职场文书
go goth封装第三方认证库示例详解
2022/08/14 Golang