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令人咋舌的隐式转换
Apr 05 MySQL
MySQL Router实现MySQL的读写分离的方法
May 27 MySQL
分析mysql中一条SQL查询语句是如何执行的
Jun 21 MySQL
Mysql数据库按时间点恢复实战记录
Jun 30 MySQL
Mysql中调试存储过程最简单的方法
Jun 30 MySQL
Mysql数据库中datetime、bigint、timestamp来表示时间选择,谁来存储时间效率最高
Aug 23 MySQL
MySQL约束超详解
Sep 04 MySQL
详细聊聊关于Mysql联合查询的那些事儿
Oct 24 MySQL
mysql sum(if())和count(if())的用法说明
Jan 18 MySQL
MySQL为数据表建立索引的原则详解
Mar 03 MySQL
MySQL Server层四个日志的实现
Mar 31 MySQL
mysql字段为NULL索引是否会失效实例详解
May 30 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实现扫描二维码根据浏览器类型访问不同下载地址
2014/10/15 PHP
php使用Cookie控制访问授权的方法
2015/01/21 PHP
微信自定义菜单的创建/查询/取消php示例代码
2016/08/05 PHP
windows7配置Nginx+php+mysql的详细教程
2016/09/04 PHP
js 禁用浏览器的后退功能的简单方法
2008/12/10 Javascript
javascript语言结构小记(一)
2011/09/10 Javascript
php对mongodb的扩展(小试牛刀)
2012/11/11 Javascript
js简易namespace管理器 实例代码
2013/06/21 Javascript
js替换字符串的所有示例代码
2013/07/23 Javascript
window.open打开页面居中显示的示例代码
2013/12/27 Javascript
浏览器兼容的JS写法总结
2016/04/27 Javascript
JS如何设置cookie有效期为当天24点并弹出欢迎登陆界面
2016/08/04 Javascript
jQuery插件easyUI实现通过JS显示Dialog的方法
2016/09/16 Javascript
JS实现iframe自适应高度的方法示例
2017/01/07 Javascript
javascript构造函数以及原型对象的理解
2017/01/13 Javascript
jquery uploadify隐藏上传进度的实现方法
2017/02/06 Javascript
深入理解nodejs搭建静态服务器(实现命令行)
2019/02/05 NodeJs
Vue配置marked链接添加target=&quot;_blank&quot;的方法
2019/07/19 Javascript
解决layui表格内文本超出隐藏的问题
2019/09/12 Javascript
JavaScript中break、continue和return的用法区别实例分析
2020/03/02 Javascript
jQuery HTML获取内容和属性操作实例分析
2020/05/20 jQuery
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
python查找第k小元素代码分享
2013/12/18 Python
Django集成百度富文本编辑器uEditor攻略
2014/07/04 Python
Python的Flask框架应用程序实现使用QQ账号登录的方法
2016/06/07 Python
Python构建XML树结构的方法示例
2017/06/30 Python
python dict 相同key 合并value的实例
2019/01/21 Python
python 猴子补丁(monkey patch)
2019/06/26 Python
详解python的变量缓存机制
2021/01/24 Python
css3 实现圆形旋转倒计时
2018/02/24 HTML / CSS
前台文员职责范本
2014/03/07 职场文书
签约仪式主持词
2014/03/19 职场文书
公民授权委托书
2014/10/15 职场文书
css3实现背景图片颜色修改的多种方式
2021/04/13 HTML / CSS
Centos系统通过Docker安装并搭建MongoDB数据库
2022/04/12 MongoDB
redis lua限流算法实现示例
2022/07/15 Redis