在MySQL数据库中,如果要插入上百万级的记录,用普通的insert into来操作非常不现实,速度慢人力成本高,推荐使用Load Data或存储过程来导入数据,我总结了一些方法分享如下,主要基于MyISAM和InnoDB引擎。

1 InnoDB存储引擎

首先创建数据表(可选),如果有了略过:

 > CREATE DATABASE ecommerce;
> USE ecommerce;
> CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
birth TIMESTAMP,
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
partition BY RANGE (store_id) (
partition p0 VALUES LESS THAN (10000),
partition p1 VALUES LESS THAN (50000),
partition p2 VALUES LESS THAN (100000),
partition p3 VALUES LESS THAN (150000),
Partition p4 VALUES LESS THAN MAXVALUE
);

然后创建存储过程,其中,delimiter命令用来把语句定界符从;变为//,不然到declare var int;遇上第一个分号MySQL就错误停止:

> use ecommerce;
> DROP PROCEDURE BatchInser IF EXISTS;
> delimiter // -- 把界定符改成双斜杠
> CREATE PROCEDURE BatchInsert(IN init INT, IN loop_time INT) -- 第一个参数为初始ID号(可自定义),第二个位生成MySQL记录个数
BEGIN
DECLARE Var INT;
DECLARE ID INT;
SET Var = 0;
SET ID = init;
WHILE Var < loop_time DO
insert into employees(id, fname, lname, birth, hired, separated, job_code, store_id) values (ID, CONCAT('chen', ID), CONCAT('haixiang', ID), Now(), Now(), Now(), 1, ID);
SET ID = ID + 1;
SET Var = Var + 1;
END WHILE;
END;
//
> delimiter ; -- 界定符改回分号
> CALL BatchInsert(30036, 200000); -- 调用存储过程插入函数

也可以把上面的内容(除了语句之前的>号)复制到MySQL查询框中执行。

2 MyISAM存储引擎

首先创建数据表(可选):

> use ecommerce;
> CREATE TABLE ecommerce.customer (
id INT NOT NULL,
email VARCHAR(64) NOT NULL,
name VARCHAR(32) NOT NULL,
password VARCHAR(32) NOT NULL,
phone VARCHAR(13),
birth DATE,
sex INT(1),
avatar BLOB,
address VARCHAR(64),
regtime DATETIME,
lastip VARCHAR(15),
modifytime TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) ENGINE = MyISAM ROW_FORMAT = DEFAULT
partition BY RANGE (id) (
partition p0 VALUES LESS THAN (100000),
partition p1 VALUES LESS THAN (500000),
partition p2 VALUES LESS THAN (1000000),
partition p3 VALUES LESS THAN (1500000),
partition p4 VALUES LESS THAN (2000000),
Partition p5 VALUES LESS THAN MAXVALUE
);

再创建存储过程:

> use ecommerce;
> DROP PROCEDURE ecommerce.BatchInsertCustomer IF EXISTS;
> delimiter //
> CREATE PROCEDURE BatchInsertCustomer(IN start INT,IN loop_time INT)
BEGIN
DECLARE Var INT;
DECLARE ID INT;
SET Var = 0;
SET ID= start;
WHILE Var < loop_time DO
insert into customer(ID, email, name, password, phone, birth, sex, avatar, address, regtime, lastip, modifytime)
values (ID, CONCAT(ID, '@sina.com'), CONCAT('name_', rand(ID)*10000 mod 200), 123456, 13800000000, adddate('1995-01-01', (rand(ID)*36520) mod 3652), Var%2, 'http:///it/u=2267714161, 58787848&fm=52&gp=0.jpg', '北京市海淀区', adddate('1995-01-01', (rand(ID)*36520) mod 3652), '8.8.8.8', adddate('1995-01-01', (rand(ID)*36520) mod 3652));
SET Var = Var + 1;
SET ID= ID + 1;
END WHILE;
END;
//
> delimiter ;

调用存储过程插入数据

> ALTER TABLE customer DISABLE KEYS;
> CALL BatchInsertCustomer(1, 2000000);
> ALTER TABLE customer ENABLE KEYS;

通过以上对比发现对于插入大量数据时可以使用MyISAM存储引擎,如果再需要修改MySQL存储引擎可以使用命令

 ALTER TABLE ecommerce ENGINE = MYISAM;

3 关于批量插入

很久很久以前,为了写某个程序,必须在MySQL数据库中插入大量的数据,一共有85766121条。近一亿条的数据,怎么才能快速插入到MySQL里呢?
当时的做法是用INSERT INTO一条一条地插入,Navicat 估算需要十几个小时的时间才能完成,就放弃了。最近几天学习了一下MySQL,提高数据插入效率的基本原则如下:

  1. 批量插入数据的效率比单数据行插入的效率高
  2. 插入无索引的数据表比插入有索引的数据表快一些
  3. 较短的SQL语句的数据插入比较长的语句快

这些因素有些看上去是微不足道的,但是如果插入大量的数据,即使很小的影响效率的因素也会形成不同的结果。根据上面讨论的规则,我们可以就如何快速地加载数据得出几个实用的结论。

  1. 使用LOAD DATA语句要比INSERT语句效率高,因为它批量插入数据行。服务器只需要对一个语句(而不是多个语句)进行语法分析和解释。索引只有在所有数据行处理完之后才需要刷新,而不是每处理一行都刷新。
  2. 如果你只能使用INSERT语句,那就要使用将多个数据行在一个语句中给出的格式:INSERT INTO table_name VALUES(...),(...),...,这将会减少你需要的语句总数,最大程度地减少了索引刷新的次数。

根据上面的结论,今天又对相同的数据和数据表进行了测试,发现用LOAD DATA速度快了不只是一点点,竟然只用了十多分钟!所以在MySQL需要快速插入大量数据时,LOAD DATA是你不二的选择。

顺便说一下,在默认情况下,LOAD DATA语句将假设各数据列的值以制表符(t)分隔,各数据行以换行符(n)分隔,数据值的排列顺序与各数据列在数据表里的先后顺序一致。但你完全可以用它来读取其他格式的数据文件或者按其他顺序来读取各数据列的值,有关细节请参照MySQL文档。

4 总结

1. 对于Myisam类型的表,可以通过以下方式快速的导入大量的数据。

ALTER TABLE tblname DISABLE KEYS;
loading the data
ALTER TABLE tblname ENABLE KEYS;

这两个命令用来打开或者关闭MyISAM表非唯一索引的更新。在导入大量的数据到一个非空的MyISAM表时,通过设置这两个命令,可以提高导入的效率。对于导入大量 数据到一个空的MyISAM表,默认就是先导入数据然后才创建索引的,所以不用进行 设置。

2. 而对于Innodb类型的表,这种方式并不能提高导入数据的效率。对于Innodb类型的表,我们有以下几种方式可以提高导入的效率:

  • 因为Innodb类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果Innodb表没有主键,那么系统会默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高 导入数据的效率。
  • 在导入数据前执行SET  UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET  UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
  • 如果应用使用自动提交的方式,建议在导入前执行SET  AUTOCOMMIT=0,关闭自动提交,导入结束后再执行

文章转自:https://www.awaimai.com/841.html

关注微信公众号:lovephp

MySQL批量插入大量数据方法的更多相关文章

  1. Mysql大量插入随机数据方法--存储过程

    创建测试表: mysql)); 创建存储过程: mysql> delimiter // mysql> create procedure rand_data(in num int) -> ...

  2. Mybatis+mysql批量插入性能分析测试

    前言 今天在网上看到一篇文章(后文中的文章指的就是它) https://www.jianshu.com/p/cce617be9f9e 发现了一种有关于mybatis批量插入的新方法,而且看了文章发现我 ...

  3. Mysql批量插入返回Id错乱(原因分析)

    在项目中经常会有如下场景: 往数据库中批量插入一批数据后,需要知道哪些插入成功,哪些插入失败了. 这时候往往会有两种思路,一个是在插入之前判断相同的记录是否存在,过滤掉重复的数据:另外一种就是边插入边 ...

  4. MySQL批量插入的分析以及注意事项

    目录 1.背景 2.两种方式对比 2.1.一次插入一条数据 2.2.一次插入多条数据 3.拓展一下 4.Other 1.背景 我们在工作中基本都会碰到批量插入数据到DB的情况,这个时候我们就需要根据不 ...

  5. mybatis+mysql批量插入和批量更新、存在及更新

    mybatis+mysql批量插入和批量更新 一.批量插入 批量插入数据使用的sql语句是: insert into table (字段一,字段二,字段三) values(xx,xx,xx),(oo, ...

  6. mybatis oracle mysql 批量插入时的坑爹问题--需谨记

    mybatis oracle mysql 批量插入一.oracle的批量插入方式insert into db(id, zgbh, shbzh) select '1', '2', '3' from du ...

  7. Oracle/Mysql批量插入的sql,效率比较高

    1.oracle 批量插入: insert into tableName(col1,col2,col3...)    select 1,'第一行第一列值','第二列值' from dual union ...

  8. mysql进阶(十五) mysql批量删除大量数据

    mysql批量删除大量数据 假设有一个表(syslogs)有1000万条记录,需要在业务不停止的情况下删除其中statusid=1的所有记录,差不多有600万条, 直接执行 DELETE FROM s ...

  9. mysql批量插入简单测试数据

    mysql批量插入简单测试数据 # 参考网址: https://www.2cto.com/database/201703/618280.html 1.mysql创建测试表 CREATE TABLE ` ...

随机推荐

  1. JDBC让java程序连上数据库(mysql数据库)

    一.小论异常: 其实JDK已经提供了一组API让java程序连上数据库,并执行SQL语句,其实说起来也蛮简单的,但是绝对是一个细致活,因为稍不留神,异常就铺天盖地的来了,下面说说这些异常吧(声明一下: ...

  2. SpringBoot | 第二十一章:异步开发之异步调用

    前言 上一章节,我们知道了如何进行异步请求的处理.除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候 ...

  3. android打开文件、保存对话框、创建新文件夹对话框(转载)

    转载地址:点击打开 这是一个简单的只有3个按钮的程序,3个按钮分别对应三种工作的模式(保存.打开和文件夹选择).封装的SimpleFileDialog.java的内容如下: package com.e ...

  4. Python接入支付宝进行PC端支付

    1.  支付宝开放平台登录,使用支付宝账号登录 https://open.alipay.com/platform/home.htm 2.选择沙箱模式 [支付宝提供了测试环境] https://docs ...

  5. docker化php项目发布方式

    在生产环境的部署中将源代码打包到镜像以docker镜像的方式发布,并且运行环境中同时包含nginx和php-fpm用脚本或者supervisor管理服务进程,这样生产服务器将不需要任何依赖,只需要安装 ...

  6. mysql服务器系统优化

    1.选择合适的IO调度 对于mysql的系统,如果是SSD,那么应该使用NOOP调度算法,如果是磁盘,就应该使用Deadline调度算法.默认是CFQ echo dealine > /sys/b ...

  7. LeetCode Search Insert Position (二分查找)

    题意: 给一个升序的数组,如果target在里面存在了,返回其下标,若不存在,返回其插入后的下标. 思路: 来一个简单的二分查找就行了,注意边界. class Solution { public: i ...

  8. 转 zigbee学习笔记---Channel、PANID、发射功率及其它参数

    现对z-stack里几个网络参数的设置以及如何获取总结一下.信道配置:Zigbee在3个频段定义了27个物理信道:868MHz频段中定义了1个20Kb/s信道,915MHz频段中定义了10个40Kb/ ...

  9. 【BZOJ1087】[SCOI2005] 互不侵犯King(状压DP)

    点此看题面 大致题意: 在\(N×N\)的棋盘里面放\(K\)个国王,使他们互不攻击,共有多少种摆放方案(国王能攻击到它周围的8个格子). 状压\(DP\) 一看到这道题我就想到了经典的八皇后问题,但 ...

  10. Count Numbers(矩阵快速幂)

    Count Numbers 时间限制: 8 Sec  内存限制: 128 MB提交: 43  解决: 19[提交] [状态] [讨论版] [命题人:admin] 题目描述 Now Alice want ...