MYSQL 大批量数据插入

最近在做MYSQL大批量数据的测试,就简单总结一下遇到的问题:

首先我是简单的写了一个MYSQL的循环插入数据的SP,具体如下:

这是插入100W数据的过程和结果,可以看到是换了55min +20S约3320秒(约300rows/s),看到之后我是只崩溃,就在网上查了些提速的方法:

0. 最快的当然是直接 copy 数据库表的数据文件(版本和平台最好要相同或相似);

1. 设置 innodb_flush_log_at_trx_commit = 0 ,相对于 innodb_flush_log_at_trx_commit = 1 可以十分明显的提升导入速度;

2. 使用 load data local infile 提速明显;

3. 修改参数 bulk_insert_buffer_size,
调大批量插入的缓存;

4. 合并多条 insert 为一条: insert into t values(a,b,c),  (d,e,f) ,,,

5. 手动使用事物;

当数据量较大时,如上百万甚至上千万记录时,向MySQL数据库中导入数据通常是一个比较费时的过程。通常可以采取以下方法来加速这一过程:

一、对于Myisam类型的表,可以通过以下方式快速的导入大量的数据。 ALTER TABLE tblname DISABLE KEYS; loading the data ALTER TABLE tblname ENABLE KEYS; 这两个命令用来打开或者关闭Myisam表非唯一索引的更新。在导入大量的数据到一个非空的Myisam表时,通过设置这两个命令,可以提高导入的效率。对于导入大量数据到一个空的Myisam表,默认就是先导入数据然后才创建索引的,所以不用进行设置。

二、对于Innodb类型的表,有以下几种方式可以提高导入的效率: ①因为Innodb类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果Innodb表没有主键,那么系统会默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高导入数据的效率。

②在导入数据前执行SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。

③如果应用使用自动提交的方式,建议在导入前执行SET AUTOCOMMIT=0,关闭自动提交,导入结束后再执行SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。

而我创建的是Innodb类型的表,分了128个分区。而我依照以上的方法,设置如下:

插入百万数据的SP如下:

可以明显的看到插入百万数据是100S左右,速度提升了33倍之多。

速度是提升了不少,那就加大插入的数据量,提升10倍,即插入千万的数据量,具体的SP如下:

可以看到时间差不多是1200s左右,因为字段加长了,可能也有影响插入的速度。

为了具体验证,就按千万行插入,字段的长度为1000字节,来查看结果,具体的SP和结果如下:

可以看到用时33min 51s月(约2031秒),即(4900row/s),速度下降很多,字符长度看来是用影响的。

varchar字段

字段的限制在字段定义的时候有以下规则:

a) 存储限制

varchar 字段是将实际内容单独存储在聚簇索引之外,内容开头用1到2个字节表示实际长度(长度超过255时需要2个字节),因此最大长度不能超过65535。

b) 编码长度限制

字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766;

  字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845。

  对于英文比较多的论坛 ,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。

  若定义的时候超过上述限制,则varchar字段会被强行转为text类型,并产生warning。

c) 行长度限制

  导致实际应用中varchar长度限制的是一个行定义的长度。 MySQL要求一个行的定义长度不能超过65535。若定义的表长度超过这个值,则提示

  ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to    change some columns to TEXT or BLOBs。

2、计算例子

  举两个例说明一下实际长度的计算。

a) 若一个表只有一个varchar类型,如定义为

create table t4(c varchar(N)) charset=gbk;

则此处N的最大值为(65535-1-2)/2= 32766。

减1的原因是实际行存储从第二个字节开始‘;

减2的原因是varchar头部的2个字节表示长度;

除2的原因是字符编码是gbk。

b) 若一个表定义为

create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;

则此处N的最大值为 (65535-1-2-4-30*3)/3=21812

减1和减2与上例相同;

减4的原因是int类型的c占4个字节;

减30*3的原因是char(30)占用90个字节,编码是utf8。

如果被varchar超过上述的b规则,被强转成text类型,则每个字段占用定义长度为11字节,当然这已经不是“varchar”了。

在mysql 中用"SHOW VARIABLES LIKE ‘%CHAR%‘"查看字符集:

再次升级插入的数据量,提升10倍,看插入的时间及占用的内存,字段的字节同样为1000,具体的SP和结果如下:

从上图可以清楚的看到,插入1亿条数据的时间为5hours +20 min+ 56s=19256s,平均插入的条数为(5193 rows/s)。根上次插入1千万条的时间差不多,再看所耗磁盘空间,用了98G的空间,跟上次插入千万条数据时的(26G-17G=9G)也是成线性关系的。按照本机500G的磁盘空间,存储1行1K字节大小的数据,本机可以存储理想极限情况下为5亿条数据,保守为4~4.5亿左右合适,以防其他的应用或者数据库的UNDO,索引空间占用。

最后再看一次查询的时间,上次插入百万数,查询数据量的时间

因为创建了索引,在查百万级的数据量时,时间是1秒左右,在数据量上升到千万时,查询1亿5百万时,时间为3Min 30S,再插入1亿数据,查询数据量,时间达到27min 43s,可见,不是线性关系,是几何级增加的。

=====================================================================================================

现在描述集群环境的测试

集群:32G内存 ,500G硬盘,3台虚拟机也就是3个节点:188.188.2.181(主节点,数据节点和SQL节点)、188.188.2.182(数据节点和SQL节点)和188.188.2.183(数据节点和SQL节点)。/root目录分区磁盘空间200G(原先默认的是50G)、插入的数据量为8000KW,所占磁盘空间为下图

插入前的内存

插入后内存

数据内存所占空间:(910051-5)*32K=27.77G  -----300W条/G

索引内存所占空间:54980*8K=430M

插入前的磁盘空间

插入后的磁盘空间

磁盘空间:200G*(34%-5%)=58G    -----143W条/G

插入前的条数

插入后的条数

条数的:82551267条

时间: 2024-11-01 16:31:23

MYSQL 大批量数据插入的相关文章

MySQL大批量数据插入,PHP之for不断插入时出现缓慢的解决方案及优化(转载)

公司有一个项目,需要频繁的插入数据到MySQL数据库中,设计目标要求能支持平均每秒插入1000条数据以上.目前功能已经实现,不过一做压力测试,发现数据库成为瓶颈,每秒仅能插入100多条数据,远远达不到设计目标. 到MySQL官方网站查了查资料,发现MySQL支持在一条INSERT语句中插入多条记录,格式如下: INSERT table_name (column1, column2, ..., columnN) VALUES (rec1_val1, rec1_val2, ..., rec1_val

解决 C++ 操作 MySQL 大量数据插入效率低下问题

往 Mysql 中,插入10000条简单数据,速度非常缓慢,居然要5分钟左右, 但是打开事务的话,一秒不到就搞定了 代码: #include <iostream> #include <winsock2.h> #include <string> #include "mysql.h" #pragma comment(lib, "libmysql.lib"); using namespace std; int main() { MYSQ

C++操作MySQL大量数据插入效率低下的解决方法

#include <iostream> #include <winsock2.h> #include <string> #include "mysql.h" #pragma comment(lib, "libmysql.lib"); using namespace std; int main() { MYSQL mysql; mysql_init(&mysql); // 初始化 MYSQL *ConnStatus = my

MYSQL培训准备(1):MYSQL 的数据插入

这些时应公司要求,需要给开发部培训一下MYSQL,所以一直在想,从什么入手,才能让各位大虾感兴趣!从语法开始吧,这能让熟悉SQL server的最快了解和感兴趣! 在MYSQL中,除了我们熟悉的INSERT INTO插入语句外,还有一个特殊的语句,REPLACE INTO语句. 1.INSERT INTO语句   语法一: INSERT [LOW_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name [(col_name,...)] VALUES (expre

mysql 将数据插入数据表乱码问题

mysql 创建数据库.数据表,默认设置是latin1_swedish_ci 所以我们创建数据库和数据表的时候应该根据自己的需要修改编码的格式,一般用utf8_general_ci 也可以用一劳永逸的方法,修改mysql的配置文件my.ini 检索[client]在她的下面添加 default-character-set=utf8 检索[mysql]和[mysqld]依次添加 default-character-set=utf8 character_set_server=utf8 保存重启环境再

SqlBulkCopy大批量数据插入到sql表中

alter TYPE TableType AS TABLE ( Name VARCHAR(50) , code VARCHAR(50) ) GO alter PROCEDURE usp_InsertProductionLocation @TVP TableType READONLY AS SET NOCOUNT ON if object_id('temp') is not null begin drop table temp end SELECT * into temp FROM @TVP; G

MySQL大批量插入数据

MySQL大批量插入数据 1. 对于Myisam类型的表,可以通过以下方式快速的导入大量的数据. ALTER  TABLE  tblname  DISABLE  KEYS; loading  the  data ALTER  TABLE  tblname  ENABLE  KEYS; 这两个命令用来打开或者关闭Myisam表非唯一索引的更新.在导入大量的数据到一 个非空的Myisam表时,通过设置这两个命令,可以提高导入的效率.对于导入大量 数据到一个空的Myisam表,默认就是先导入数据然后才

mysql大批量插入数据的4种方法示例

前言 本文主要给大家介绍了关于mysql大批量插入数据的4种方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 方法一:循环插入 这个也是最普通的方式,如果数据量不是很大,可以使用,但是每次都要消耗连接数据库的资源. 大致思维如下 (我这里写伪代码,具体编写可以结合自己的业务逻辑或者框架语法编写) ? 1 2 3 4 5 6 7 8 9 10 11 12 13 for($i=1;$i<=100;$i++){  $sql = 'insert...............';  /

向mysql中批量插入数据的性能分析

MYSQL批量插入数据库实现语句性能分析 假定我们的表结构如下 代码如下   CREATE TABLE example (example_id INT NOT NULL,name VARCHAR( 50 ) NOT NULL,value VARCHAR( 50 ) NOT NULL,other_value VARCHAR( 50 ) NOT NULL) 通常情况下单条插入的sql语句我们会这么写: 代码如下   INSERT INTO example(example_id, name, valu