MySQL性能研究之插入优化

news/2024/5/18 23:11:16 标签: mysql, 数据库, jdbc, 存储, 网络
 本文出自:http://blog.csdn.net/hongchangfirst

 序言

        这篇文章研究了在海量数据需求下,MySQL数据库的承载能力。如果读者想尽快的获得帮助,而不想纠于细节,可以只看第一章;如果读者想具体了解结论是怎么得到的,是通过什么方式,可以继续看第二章;当然,所有的实验环境和部分SQL代码在第三章里指出,这一章读者可以快速浏览,以达到管中窥豹的效果。如有任何疑问可以和我联系。原文来自http://blog.csdn.net/hongchangfirst/article/details/6947129。

 

第一章  概述

1.1 摘要

        本文通过对MySQL数据库(Win32)进行各种方法下的插入操作,研究了MySQL数据库在各种情况下,对插入操作的吞吐量和性能瓶颈所在,并指出通过“缓存”加“批处理”的方式可以使MySQL数据库的吞吐量达到每分钟46MB,可以满足目前大部分应用。

1.2 结论

        根据目前的实验,在现行实验环境下(见第三章),MySQL至少能支持每分钟46MB的插入数据量,所以每天能插入的数据量至少为64GB。

        虽然实验结果是在Windows平台下得到的,但由于在Linux平台下和Windows平台下MySQL数据库的吞吐量并不会有数量级的差别,所以本文的结论也适用于Linux平台。

1.3 系统性能瓶颈结论

        1.  网络带宽并不是MySQL数据库插入操作的性能瓶颈。

        2.  每次插入两条数据的存储过程比着每次插入一条数据的存储过程,吞吐量大致得到两倍的提升。说明应用和数据库之间的JDBC开销正是MySQL数据库插入操作的性能瓶颈。

        3.  每次插入四十条数据的存储过程比每次插入一条数据的存储过程性能提高了40倍,说明此时JDBC仍然是系统的性能瓶颈,仍然可以通过提升JDBC效率(如增加一次通信插入的数据量)来提高系统的吞吐量,直到其不再是系统的性能瓶颈。

        4.  并发操作并不能增加系统的吞吐量,所以系统的瓶颈不在并发。

1.4 MySQL自身对插入的优化

        1. 使用insert into tablename values(),(),()...语法。

        2. 如果有索引,批处理插入前先把建索引disable了,插入完成后再从新建索引。

        3. 插入前对表进行加锁,插入完后,再解锁。

        4. 使用插入延迟,当客户使用插入延迟,服务器立刻返回,数据库自己对缓冲区做处理。

        5.使用 LOAD DATA INFILE,把文件中的数据直接映射成表。这个技术我认为实际上是利用了缓存加批处理,另外加上2、3、4的方式,所以速度超过。但是使用时要注意文件的编码格式。

第二章  实验

2.1 单机节点和insertToemployee的插入

        利用单机节点(应用和MySQL服务器运行于同一台计算机上)和存储过程insertToemployee(详见3.5)进行数据的插入,实验结果如表2. 1所示。从中我们可以看出,插入的数据量基本与时间成线性关系,每分钟插入的数据量平均在1.3MB左右。

表2.1单机节点和存储过程insertToemployee插入表

时间(分钟)

记录数

数据量(MB)

1

2645

1.29

2

5332

2.60

5

13657

6.67

10

28122

13.73

2.2 网络节点和insertToemployee的插入

        利用网络节点(应用和MySQL服务器运行于两台计算机上)和存储过程insertToemployee进行数据的插入,实验结果如表2. 2所示。从中我们可以看出,插入数据量基本与时间成线性关系,每分钟插入的数据量平均在1.3MB左右;同时,与2.1的实验相比,网络节点间的插入和单机节点间的插入性能差不多(甚至利用网络更好一点,可能是单机节点情况下,要进行应用进程和MySQL服务器进程之间的调度所花费的开销),证明网络带宽并不是性能的瓶颈。

表2.2网络节点和存储过程insertToemployee插入表

时间(分钟)

记录数(行)

数据量(MB)

1

2788

1.36

2

5446

2.66

5

14002

6.84

10

26461

12.92

2.3 单机节点和insertToemployee2的插入

        利用单机节点和存储过程insertToemployee2(详见3.5)进行数据的插入,实验结果如表2. 3所示。

表2.3单机节点和存储过程insertToemployee2插入表

时间(分钟)

记录数

数据量(MB)

1

5300

2.58

2

11156

5.44

5

27634

13.50

10

54100

26.42

2.4 网络节点和insertToemployee2的插入

        利用网络节点和存储过程insertToemployee2进行数据的插入,实验结果如表2. 4所示。

表2.4网络节点和存储过程insertToemployee2插入表

时间(分钟)

记录数

数据量(MB)

1

5516

2.70

2

11136

5.44

5

27158

13.26

10

54158

26.44

        根据实验2.3和2.4,我们可以看出,应用一次向MYSQL数据库发送一条插入操作和两条插入操作,吞吐量基本上得到了两倍的提升,所以这说明应用和MySQL数据库之间的连接开销(JDBC)是MySQL数据库插入操作的性能瓶颈。所以我们可以通过继续提升JDBC的效率来提高MySQL数据库的吞吐量。

2.5 网络节点和insertToemployee20的插入

        由于JDBC是系统性能的瓶颈,所以现在研究一下,每次插入20条数据系统的吞吐量。从表2. 5中可以看出,MySQL能满足每分钟插入22MB数据的要求。吞吐量与每次插入的条数基本上成线性关系,说明每次插入20条数据时(数据量为10KB),JDBC仍然是系统性能的瓶颈所在。

        所以,仍然可以继续通过提升JDBC的效率(如增加每次插入记录的条数),来增加系统的性能,直到JDBC不再是系统的性能瓶颈。

表2.5网络节点和存储过程insertToemployee20插入表

时间(分钟)

记录数

数据量(MB)

1

45520

22.23

2

101840

49.72

5

228260

111.45

10

475060

231.96

2.6 网络节点和insertToemployee40的插入

        所以,继续增加一次通信插入的数据量,这次使每次插入40条记录,试验结果如表2. 6所示。

表2.6网络节点和存储过程insertToemployee40插入表

时间(分钟)

记录数

数据量(MB)

1

96000

46.88

2

197920

96.64

5

368960

180.16

10

942360

460.14

        从表2. 6中可以看出,每次插入40条记录,系统能满足每分钟插入46MB数据的要求。性能仍然得到了线性的增长,说明此时JDBC仍然是系统性能的瓶颈。所以,仍然可以继续增加每次插入记录的条数,用以增加系统的性能,直到JDBC不再是系统的性能瓶颈,由于篇幅所限,继续提升JDBC效率的实验暂做到这里。

2.7 网络节点和insertToemployee的并发(多线程)插入

        利用网络节点和存储过程insertToemployee进行数据的并发插入,用两个线程分别插入数据,得到实验结果如表2. 7所示。

表2.7网络节点和存储过程insertToemployee的多线程插入表

时间(分钟)

线程号

记录数

数据量(MB)

总数据量(MB)

1

thread1

1344

0.66

1.31

thread2

1348

0.66

2

thread1

2693

1.31

2.63

thread2

2693

1.31

        可以看出,多线程并不增加系统的吞吐量,所以多线程并不是系统性能瓶颈所在。

2.8 网络节点和insertToemployee的并发(多进程)插入

表2. 8网络节点和存储过程insertToemployee的多进程插入表

时间(分钟)

线程号

记录数

数据量(MB)

总数据量(MB)

1

process1

1350

0.66

1.33

process2

1375

0.67

2

process1

2782

1.36

2.61

process2

2789

1.36

        可以看出,多进程并不增加系统的吞吐量,所以多进程并不是系统性能瓶颈的所在。究其原因有可能是因为插入的是同一个表,数据库对其进行了加锁,所以多个连接只能顺序的插入,是否如此详见2.9实验。

2.9 向不同的表同时插入数据

        利用网络节点和存储过程insertToemployee和存储过程insertTostudent(详见3.5)进行数据的并发(多进程)插入,process1向student表插入数据,process2向employee表插入数据(student表和employee表除了表名不一样外,其他都一样),得到的实验结果如表2. 7所示。

表2.9不同的表同时插入数据实验

时间(分钟)

进程号

记录数

数据量(MB)

总数据量(MB)

1

student

process1

1312

0.64

1.28

employee

process2

1319

0.64

2

student

process1

2809

1.37

2.76

employee

process2

2854

1.39

        可以看出,系统的吞吐量并没有得到提升,所以数据库并没有对表进行加锁,是MySQL自身的吞吐量限制了吞吐量的提升。

2.10 各阶段开销

        我们首先研究下不同阶段所花费的时间为多少,进而为我们优化数据库应用铺平道路。一条数据从应用开始到最终被插入在数据库中,我们粗浅的把它分为三个阶段:数据准备时间、连接时间、插入时间。

表2.10两分钟各阶段执行次数

存储过程

准备数据

准备数据+连接

准备数据+连接+执行插入操作

insertToemployee

21131919

158064

5380

insertToemployee2

21429164

298310

8360

        从表2. 10,我们可以得到下表。表2. 11表示每次所花费的时间。

表2.11各阶段每次迭代执行时间(ms)

 

准备数据

准备数据+连接

准备数据+连接+执行插入操作

insertToemployee

0.00567

0.75758

22.02643

insertToemployee2

0.01120

0.80453

28.70813

        从表2. 11,我们可以得到每个阶段所花费的时间,如下表。

表2. 12各阶段每次执行时间(ms)

 

准备数据

连接

执行插入操作

insertToemployee

0.00567

0.75191

21.26885

insertToemployee2

0.01120

0.79333

27.90360

去除准备数据花费的时间后,对连接和执行插入操作进行归一化处理。

表2. 12各阶段所占开销百分比

操作

时间百分比

insertToemployee

insertToemployee2

连接

3.41%

2.76%

插入操作

96.59%

97.24%

        可以看到,随着每次插入条数的增多,连接所占花费的百分比就下降了。因为虽然每次传输两条记录比每次传输一条记录(0.79333>0.75191)所用的时间更长,但是与插入操作(27.90360>21.26885)相比,连接所花费的时间增长相对较慢,这样就充分的利用了JDBC。

 

 

第三章 实验环境

3.1 节点配置

 

应用服务器

MySQL服务器

硬件环境

CPU

Intel Core 2 E7500 @ 2.93GHz 2.93GHz

Intel Core 2 E7500 @ 2.93GHz 2.94GHz

RAM

1.87GB

2.00GB

软件环境

OS

WinXP 32-bit

Win7 32-bit

3.2 数据库环境

类型

版本

MySQL

mysql-5.5.17-win32

桥接器

mysql-connector-java-5.1.18

3.3 局域网

        传输速率为100Mbps的以太网。根据局域网一般的效率而言,大概能维持在600MB/Min。

3.4 数据库

CREATE TABLE employee

 (

id int(8),

id2 decimal(20,4),

name char(40),

name2 varchar(200),

name3 char(200)

) ;

employee表中每条记录大约为500字节的数据量。

 

CREATE TABLE student

 (

id int(8),

id2 decimal(20,4),

name char(40),

name2 varchar(200),

name3 char(200)

) ;

student表中每条记录大约为500字节的数据量。

3.5 存储过程

#insertToemployee存储过程每次插入一条数据

delimiter //

create procedure insertToemployee

(in id int(8),in id2 decimal(20,4),in name char(40),in name2 char(200),in name3 char(200))

begin

insert into employee values(id,id2,name,name2,name3);

end

//

 

#insertToemployee2存储过程每次插入两条数据

delimiter //

create procedure insertToemployee2

(

in id int(8),in id2 decimal(20,4),in name char(40),in name2 char(200),in name3 char(200),

in ids int(8),in id2s decimal(20,4),in names char(40),in name2s char(200),in name3s char(200)

)

begin

insert into employee values(id,id2,name,name2,name3),(ids,id2s,names,name2s,name3s);

end

//

存储过程insertToemployee20和存储过程insertToemployee40与insertToemployee2类似,这里为了减少篇幅,不再赘述。

 

版权所有,转载请注明出处http://blog.csdn.net/hongchangfirst

 

微笑


http://www.niftyadmin.cn/n/748399.html

相关文章

Java8 并行流原理

目录一、并行流的简单使用1、我的CPU为8核,为啥只有七条线程?2、如何控制parallize的线程数?二、源码解析一、并行流的简单使用 public static void main(String[] args) throws InterruptedException {//设置睡眠时间,方便visual…

衡量易操作数据存储(SOD)可扩展性能的十大准则(上)

这篇文章来自作者对Michael Stonebraker和Rick Cattell两位作者所著《10 Rules for scalable Performance in ‘simple operation’ Datastores 》 Communications of The ACM | June 2011 | VOL. 54 | No. 6 的翻译和理解,以飨读者,分为上、…

Java List与数组之间的转换 - CSDN博客(转载整合)

注意List 集合给我们提供了一个把LIst转为数组的方法, toArray();但是这个方法返回的类型是 Object[ ] ;如果我们要是想强转为我们想要的类型,比如说是字符串数组类型 ...采用集合的toArray()方法直接把List集合转换成数组&#xff0c…

JVM(九)对象的实例化内存布局与访问定位

目录相关面试题对象的实例化创建对象的方式对象创建步骤第一步:判断对象对应的类是否加载,链接,初始化第二步:为对象分配内存第三步 处理并发安全问题第四步 属性的默认初始化第五步 设置对象的对象头第六步 执行init方法进行初始…

衡量易操作数据存储(SOD)可扩展性能的十大准则(中)

这篇文章来自作者对Michael Stonebraker和Rick Cattell两位作者所著《10 Rules for scalable Performance in ‘simple operation’ Datastores 》 Communications of The ACM | June 2011 | VOL. 54 | No. 6 的翻译和理解,以飨读者,分为上、…

Redis底层

目录1、什么是redis2、应用场景3、DB数据结构3.1、RedisDB数据结构:redis数据库默认有16个库。3.2、Redis的五种数据结构的内部编码4、String数据结构4.1、redis3.2以前sds4.1、redis3.2后sds5、bitMap(bitset,位图)数据结构6、list数据结构6.1、redis阻…

一个程序员的心理历程

30.有时,追求效率是一种美丽的错误。 29.有人问我,什么是幸福。 我说,晚饭后,我和爸爸妈妈坐在沙发上,一起聊着今天发生的事情,是幸福; 我还说,我和妻子静静的躺在床上,…