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 使用SQL语句修改表名的实现
Apr 07 MySQL
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
May 06 MySQL
详解MySQL主从复制及读写分离
May 07 MySQL
JDBC连接的六步实例代码(与mysql连接)
May 12 MySQL
MySQL如何构建数据表索引
May 13 MySQL
正确使用MySQL update语句
May 26 MySQL
MySQL中InnoDB存储引擎的锁的基本使用教程
May 26 MySQL
SQL实现LeetCode(180.连续的数字)
Aug 04 MySQL
MySQL中order by的使用详情
Nov 17 MySQL
mysql字段为NULL索引是否会失效实例详解
May 30 MySQL
mysql查看表结构的三种方法总结
Jul 07 MySQL
MySQL事务的ACID特性以及并发问题方案
Jul 15 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下编码转换函数mb_convert_encoding与iconv的使用说明
2009/12/16 PHP
创建配置文件 用PHP写出自己的BLOG系统 2
2010/04/12 PHP
PHP获取搜索引擎关键字来源的函数(支持百度和谷歌等搜索引擎)
2012/10/03 PHP
Yii多表联合查询操作详解
2016/06/02 PHP
PHP给前端返回一个JSON对象的实例讲解
2018/05/31 PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
2020/02/16 PHP
一起来写段JS drag拖动代码
2010/12/09 Javascript
js 本地预览的简单实现方法
2014/02/18 Javascript
用nodejs实现PHP的print_r函数代码
2014/03/14 NodeJs
jQuery ajaxSubmit 实现ajax提交表单局部刷新
2016/07/04 Javascript
JavaScript实现各种排序的代码详解
2017/08/28 Javascript
jquery手机触屏滑动拼音字母城市选择器的实例代码
2017/12/11 jQuery
详解Javascript 中的 class、构造函数、工厂函数
2017/12/20 Javascript
使用Angular CLI进行Build(构建)和Serve详解
2018/03/24 Javascript
使用vue2实现带地区编号和名称的省市县三级联动效果
2018/11/05 Javascript
jquery实现Ajax请求的几种常见方式总结
2019/05/28 jQuery
vue中使用element ui的弹窗与echarts之间的问题详解
2019/10/25 Javascript
vue中更改数组中属性,在页面中不生效的解决方法
2019/10/30 Javascript
详解vue-template-admin三级路由无法缓存的解决方案
2020/03/10 Javascript
vue路由跳转传递参数的方式总结
2020/05/10 Javascript
微信小程序开发打开另一个小程序的实现方法
2020/05/17 Javascript
python网络编程之数据传输UDP实例分析
2015/05/20 Python
python递归查询菜单并转换成json实例
2017/03/27 Python
利用pandas读取中文数据集的方法
2018/07/25 Python
python实现推箱子游戏
2020/03/25 Python
详解Python数据分析--Pandas知识点
2019/03/23 Python
Python实现微信消息防撤回功能的实例代码
2019/04/29 Python
django框架事务处理小结【ORM 事务及raw sql,customize sql 事务处理】
2019/06/27 Python
python flask 如何修改默认端口号的方法步骤
2019/07/12 Python
python使用paramiko模块通过ssh2协议对交换机进行配置的方法
2019/07/25 Python
css3翻牌翻数字的示例代码
2020/02/07 HTML / CSS
印度排名第一的蛋糕、鲜花和礼品送货:Winni
2019/08/02 全球购物
高中同学聚会邀请函
2014/01/11 职场文书
项目合作意向书模板
2014/07/29 职场文书
计算机实训报告范文
2014/11/05 职场文书
酒店前台辞职书
2015/02/26 职场文书