MySQL 亿级数据导入导出及迁移笔记

最近MySQL的笔记有点多了,主要是公司Oracle比较稳定维护较少,上周被安排做了一个MySQL亿级数据的迁移,趁此记录下学习笔记;

数据迁移,工作原理和技术支持数据导出、BI报表之类的相似,差异较大的地方是导入和导出数据量区别,一般报表数据量不会超过几百万,而做数据迁移,如果是互联网企业经常会涉及到千万级、亿级以上的数据量。

导入和导出是两个过程,即使做数据迁移我们也要分开来看,同时,导入/导出方式又分为:

1、MySQL自带导入/导出方式

2、各类客户端导入/导出方式

先总结下导出:

1、导出对于字段较少/字段内容较少的数据,通过客户端方式可以采用navicat等工具导出,我这里本次导出三个字段,都是11位数字以内的值,用navicat导出每分钟大约250万数据,

2、MySQL自带的导出语句:select into outfile语句;

SELECT ... FROM TABLE_A --可以加where条件
INTO OUTFILE "/path/to/file" --导出文件位置
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' -- 字段分割符和包含符
LINES TERMINATED BY '\n';--换行符

这里fields之前很简单都可看懂,不做说明,讲下fields之后的:

FIELDS TERMINATED BY ',' 代表我字段和字段之间用 逗号 分开 ,如:字段 A 字段 B,导出时候显示格式为:A,B

OPTIONALLY ENCLOSED BY '"' 代表字段内容用双引号包含,导出格式如: "A","B"

LINES TERMINATED BY '\n';每条数据换行区分,导出格式如:

"A","B"

"A1","B1"

当然,字段区分和包含符号可以自行定义,定义为:'    #  都可以

用MySQL自带导出/导入优点是速度极快,缺点是:只能导出文件是在服务器主机所在的本机地址,对于bi之类拿到不数据库主机权限的同事这个方式可能奢望了。不过好在对于字段/内容较少的报表第三方客户端工具导出速度也不算特别慢;

导入:

重点记录导入,导入主要是dba做数据迁移了,方式也分客户端和MySQL自带方式:

这里极度推荐用MySQL导入方式,原因是我之前要迁移1.3亿数据,用navicat客户端导入数据要22小时,耗时太长且不确定太多,本身navicat等工具就会有假死风险的存在,所不建议超过1万以上的数据通过navicat导入;

MySQL自带导入方式:

--官方文档定义如下,注释是我自己理解添加的:

LOAD DATA 、
[LOW_PRIORITY | CONCURRENT]--无人使用数据库再执行/立即执行
[LOCAL]--带这个参数指服务端即不是服务器主机上读取文件,不带这个参数是默认在服务器主机上读取文件
INFILE 'file_name' --读取文件地址、文件名
    [REPLACE | IGNORE]--遇到重复数据是:替换/重复写入,建议使用ignore重复写入
    INTO TABLE tbl_name --导入到那个表
    [PARTITION (partition_name [, partition_name] ...)]--这行参数可以不要,建议用后面的fields
    [CHARACTER SET charset_name]--设定导入内容字符格式,utf-8还是GBK等都可以指定

    [{FIELDS | COLUMNS}  --fields标识符
        [TERMINATED BY 'string'] --系统字段通过什么符号区分
        [[OPTIONALLY] ENCLOSED BY 'char']--系统字段本身的起始和结束用什么符号区分
        [ESCAPED BY 'char']--转义符,如果是文本文件,在文本字段中有特殊字符如双引号,可通过定义转义符忽略文本文件特殊字符
    ]
    [LINES  --lines标识符
        [STARTING BY 'string'] --定义行开头的字符串,如果行开头没有字符标识,一般可以不写
        [TERMINATED BY 'string']--行结束字符串标识,通过定义字符来区分行与行的数据
    ]
    [IGNORE number {LINES | ROWS}]--忽略文件中前面多少行,一般都不写
--后面都是指定插入到哪些字段
    [(col_name_or_user_var
        [, col_name_or_user_var] ...)]
    [SET col_name={expr | DEFAULT},
        [, col_name={expr | DEFAULT}] ...]

原文上说的用load data能速度极快的导入数据到数据库中,但是如果要使用fields和lines参数,则必须要带一个参数值且fields必须在lines参数之前;

本次我使用的语句是:

load data infile '/data/files/T_CUST_INFO.txt' --默认指定服务器文件夹
ignore into table t_dq_user --允许重复记录插入
fields terminated by ','  --判断字段通过逗号标识来分隔开
lines terminated by '\n'(CustID,DeviceNo,logintype);--通过换行标识来解析成为每一条数据和插入到我指定的字段

插入是很简单的语句,这里我不做具体举例操作,我要分享的是如何提高插入效率;

因为在我第一次用语句插入的时候,从晚上12点开始执行,到第二天11点还没有执行完。所以不是说用了load不配置其他的就一定很快;

本次我插入的数据格式如图:

文本格式如下:

一共有1亿4千万条数据,以文本文档的形式导出的,有4.3G大小;通过ftp软件上传到服务器/data/files文件夹中;

吐槽点1:

由于项目要求三个字段都要有索引,所以我在建表的时候就加了索引,导致耗时遥遥无期;

原因:

索引是要占空间的,如果导入三个字段都要加索引,代表了我要每个字段都写入索引一次,耗时比不加索引多了几倍;

优化方法:

导入前把表的索引去掉留自增id一个,等导入完之后再添加

吐槽点2:

engine的选择:

MySQL的engine对如load写入是不一样的,特别是有master-slave主从备份的机制:

对MyISAM引擎: 
          (1)对master服务器进行  ‘load' 操作, 
          (2)在master上所操作的load.txt文件,会同步传输到slave上,并在tmp_dir 目录下生成 load.txt文件 
               master服务器插入了多少,就传给slave多少 
          (3)当master上的load操作完成后,传给slave的文件也结束时, 
               即:在slave上生成完整的 load.txt文件 
               此时,slave才开始从 load.txt 读取数据,并将数据插入到本地的表中

对innodb引擎: 
          (1)主数据库进行  ‘Load' 操作 
          (2)主数据库操作完成后,才开始向slave传输 load.txt文件, 
               slave接受文件,并在 tmp_dir 目录下生成 load.txt 文件 
               接受并生成完整的load.txt 后,才开始读取该文件,并将数据插入到本地表中

所以追求极致速度,几十亿数据的,可以考虑选择myisam引擎,MySQL默认应该是innodb;不过本次我并没有更改引擎,本人不推荐更改默认的innodb引擎,毕竟Oracle官方主推引擎,综合性最强,除非有特殊性,不推荐使用myisam。如果用了myisam,注意一下两点:

用了myisam,可以调整几个session值扩大读取内存,提高读取数据,语句如下:

SET SESSION BULK_INSERT_BUFFER_SIZE = 256217728 ;
SET SESSION MYISAM_SORT_BUFFER_SIZE = 256217728 ; 

对于MyISAM引擎,导入前的唯一校验可以先关闭,之后再打开:

SET UNIQUE_CHECKS=0 --关闭

SET UNIQUE_CHECKS=1 --打开

吐槽点3:

虽然MySQL支持本地客户端读取文件,但是由于各种网络原因,在几十几百条数据的情况下没有什么影响,但是到了亿级数据量,即使1毫秒的影响也会放的特别大,所以建议用ftp传到服务器上进行读取

吐槽点4:

经验分享,导入之后看看服务器状态:top 命令看看主机cpu MySQL占用情况,理论上会占用较多cpu,我的第一次耗时贼长的那次,cpu占用10%,这是极度不正常的导入,第二次正常导入cpu占用到了110%,这才是再急速写入的状态;最后1.4亿数据只耗时:7分多中,所以一定要在执行语句后监控下服务器,否则语句不一定在正常执行。

cpu占用:

注意:load和insert最大的区别是:load只操作语法一次,之后就是一直是数据批量插入,而insert 是每一个数据操作一次,也遍历一次字段索引,所以insert本身对于大数据来说是极慢的。

总结:

本次优化我感觉最大最明显的变化是,去除索引后,导入速度极快,索引,重要的事情再说一遍:

导入时候可以先去掉索引,导入完之后再添加。

2020.7.3更新

MySQL导入大数据时一定要注意max最大事物限制,前几个月在做数据迁移时,在MySQL8.0 MGR集群上发生了大事物限制导致实例出问题重启了MySQL,默认配置应该是一亿五千万的事物限制,当时导入的数据比较大也没做参数扩展同时也没做数据切分导入或者限流导入,导致数据库堵塞重启,按照公司要求7*24*365机制,这算是事故了,如果高要求的公司,建议导入的时候注意MySQL本身配置或者导入进行事物提交限制;

到此这篇关于MySQL 亿级数据导入导出及迁移笔记的文章就介绍到这了,更多相关MySQL 亿级数据导入导出及迁移内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何使用分区处理MySQL的亿级数据优化

    mysql在查询上千万级数据的时候,通过索引可以解决大部分查询优化问题.但是在处理上亿数据的时候,索引就不那么友好了. 数据表(日志)是这样的: 表大小:1T,约24亿行: 表分区:按时间分区,每个月为一个分区,一个分区约2-3亿行数据(40-70G左右). 由于数据不需要全量处理,经过与需求方讨论后,我们按时间段抽样一部分数据,比如抽样一个月的数据,约3.5亿行. 数据处理的思路: 1)建表引擎选择Innodb.由于数据是按月分区的,我们将该月分区的数据单独copy出来,源表为myisam引擎

  • 浅谈MySQL 亿级数据分页的优化

    背景 下班后愉快的坐在在回家的地铁上,心里想着周末的生活怎么安排. 突然电话响了起来,一看是我们的一个开发同学,顿时紧张了起来,本周的版本已经发布过了,这时候打电话一般来说是线上出问题了. 果然,沟通的情况是线上的一个查询数据的接口被疯狂的失去理智般的调用,这个操作直接导致线上的MySql集群被拖慢了. 好吧,这问题算是严重了,下了地铁匆匆赶到家,开电脑,跟同事把Pinpoint上的慢查询日志捞出来.看到一个很奇怪的查询,如下 POST domain/v1.0/module/method?ord

  • mysql数据库如何实现亿级数据快速清理

    今天收到磁盘报警异常,50G的磁盘被撑爆了,分析解决过程如下: 1. 进入linux服务器,查看mysql文件夹中各个数据库所占的磁盘空间大小 看到了吗,光olderdb就占了25G 2. 用SQLyog登录mysql数据库,查看数据库各个表的占用空间情况 SELECT CONCAT(table_schema,'.',table_name) AS 'aaa', table_rows AS 'Number of Rows', CONCAT(ROUND(data_length/(1024*1024*

  • MySQL 亿级数据导入导出及迁移笔记

    最近MySQL的笔记有点多了,主要是公司Oracle比较稳定维护较少,上周被安排做了一个MySQL亿级数据的迁移,趁此记录下学习笔记: 数据迁移,工作原理和技术支持数据导出.BI报表之类的相似,差异较大的地方是导入和导出数据量区别,一般报表数据量不会超过几百万,而做数据迁移,如果是互联网企业经常会涉及到千万级.亿级以上的数据量. 导入和导出是两个过程,即使做数据迁移我们也要分开来看,同时,导入/导出方式又分为: 1.MySQL自带导入/导出方式 2.各类客户端导入/导出方式 先总结下导出: 1.

  • Linux下mysql数据库的创建导入导出 及一些基本指令

    首先linux 下查看mysql相关目录 查看 mysql 的安装路径 执行查询 SQL mysql>show variables like '%dir%'; datadir 就是数据路径 确定了运行路径,执行导入.导出mysql数据库命令 一.导出数据库用mysqldump命令 (注意:先cd到mysql的运行路径下,再执行一下命令): 1.导出数据和表结构: mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql 注意 我的服务器配置权限特殊 因此需要用 muysqldu

  • MySQL 表数据的导入导出操作示例

    本文实例讲述了MySQL 表数据的导入导出操作.分享给大家供大家参考,具体如下: 数据导出 1.  使用 SELECT ...INTO OUTFILE ...命令来导出数据,具体语法如下. mysql> SELECT * FROM tablename INTO OUTFILE 'target_file' [option]; 其中 option 参数可以是以下选项: FIELDS TEMINATED BY 'string' (字符分断符) FIELDS [OPTIONALLY] ENCLOSED

  • docker镜像导入导出备份迁移的操作

    导出: docker save -o centos.tar centos:latest #将centos:latest镜像导出为centos.tar文件 导入: docker load -i centos.tar #加载centos.tar,加载后的镜像各标签与原导出的镜像标签相同 补充知识:docker将镜像保存为tar文件 将单个文件保存为tar文件,并加载到本地 docker save ****.v1 > images.tar docker load < images.tar 将多个文件

  • MySQL数据备份、还原、数据库迁移以及表的导出和导入

    目录 前言 一.数据备份 1.使用mysqldump命令备份 2.直接复制整个数据库目录 3.使用mysqlhotcopy工具快速备份 二.数据还原 1.使用mysql命令还原 2.直接复制到数据库目录 三.数据库迁移 1.相同版本的MySQL数据库之间的迁移 2.不同版本的MySQL数据库之间的迁移 四.表的导出和导入 1.用select…into outfile导出文本文件 2.用mysqldump命令导出文本文件 3.用mysql命令导出文本文件 4.用load data infile方式

  • mysql导入导出数据中文乱码解决方法小结

    linux系统中 linux默认的是utf8编码,而windows是gbk编码,所以会出现上面的乱码问题. 解决mysql导入导出数据乱码问题 首先要做的是要确定你导出数据的编码格式,使用mysqldump的时候需要加上--default-character-set=utf8, 例如下面的代码: 复制代码 代码如下: mysqldump -uroot -p --default-character-set=utf8 dbname tablename > bak.sql 那么导入数据的时候也要使用-

  • Mysql导入导出工具Mysqldump和Source命令用法详解

    在PHP网站开发中,时常遇到Mysql数据库备份或数据库迁移工作,这时Mysql怎么导入导出数据库中的数据就非常关键,Mysql本身提供了命令行导出工具Mysqldump和Mysql Source导入命令进行SQL数据导入导出工作,通过Mysql命令行导出工具Mysqldump命令能够将Mysql数据导出为文本格式(txt)的SQL文件,通过Mysql Source命令能够将SQL文件导入Mysql数据库中,下面通过Mysql导入导出SQL实例详解Mysqldump和Source命令的用法. M

  • Mysql导入导出时遇到的问题解决

    背景 自从把我手上的任务全部转换成docker运行和管理之后,遇到了一系列的坑,这次是mysql备份的问题. 原因是启动mysql镜像的时候没有指定-v,导致一段时间之后docker很大,原来的磁盘不够了,需要迁移到新磁盘. 在使用导入导出的时候出现了一些问题,浪费了很多时间去解决. 解决过程 定位mysql镜像过大 查看容器占用的空间 ```docker system df``` 查看详细信息 Local Volumes space usage: VOLUME NAME LINKS SIZE

随机推荐