MySQL 性能测试经验
一、背景
近期在进行资源调度管理平台的重构工作,其中的Resource/Property数据库设计,在没有更加优化的方案前,打算沿用当前平台的数据库结构;这就需要对当前平台的数据库结构进行剖析研究,并对其性能进行测试与分析,得出的数据结果作为后续设计和优化的参考。
二、测试方法
1、测试工具:mysqlslap,mysqlslap是MySQL5.1.4之后自带的benchmark基准测试工具,该工具可以模拟多个客户端同时并发的向服务器发出查询更新,给出了性能测试数据而且提供了多种引擎的性能比较。官方介绍:http://dev.mysql.com/doc/refman/5.6/en/mysqlslap.html,
使用方法:http://my.oschina.net/moooofly/blog/152547
2、测试流程:建立测试数据库database和待测试的表tables → 根据table的结构,利用脚本生成一定数量的有效随机数据 → 利用mysqlslap对相应query语句进行测试 → 结果数据的分析。
3、关键语句:考虑到资源平台的实际应用情况,通过资源属性查询资源的操作为主要操作,且这类操作的耗时占总操作耗时的比例为最大,故对应这类操作的查询语句为关键语句,对整个数据库性能影响很大,我们可以通过测试这个关键语句得出的结果来评估整个数据库的性能。
三、测试过程
1、建表:
通过属性查询资源需要两张表:设备表device和设备属性对应表deviceattr。device表对应资源,记录资源的基本信息,如name,type,group,creator等等;deviceattr表对应资源和属性的关系,记录每个资源的每个属性和属性值;它们的结构如下所示:
通过多个属性组合查询deviceattr表,获得相应的id ,id即是满足条件的设备id,进而能直接在device表中查询得到其基本属性。
本次测试的关键语句即是从deviceattr表中组合查询出满足条件的id,故本测试只需要用到deviceattr一张表。
2、生成随机数据并插入相应的表中:
这里编写了几个生成随机数据的sql函数rand_name(),rand_value(),rand_num(),rand_creator(),并编写了存储过程insert_devattr,用来将一定量数据批量插入deviceattr表中。
然后将整个建表和存储数据的过程写进一个sql脚本中,并在mysql中运行这个脚本,待测试的表和数据就建立好了。(sql脚本在附录)如下图所示,生成的deviceattr随机数据有4020条:
3、利用mysqlslap进行测试:
整个数据库的关键操作为通过属性查询资源,该操作的关键sql语句就是:
select id from deviceattr where [ n attr ] group by id;
例:查询拥有attr10或者attr20属性的所有资源的id为:
select id from deviceattr where name = ‘attr10’ or name = ‘attr20’ group by id;
在建立好待测数据库后,就可以利用mysqlslap进行测试,mysqlslap命令如下所示:
shell < mysqlslap --create-schema='test1' --query="select id from deviceattr where name='attr10' or name='attr20' group by id;" -c 50 -i 100
以上语句表示:使用test1数据库,使用query所指定的语句,测试50个并发查询,每一个查询100次。
该语句的测试结果如下图所示:
结果中可以看到执行语句的平均耗时,最大耗时和最小耗时,并发线程数等等。
四、结果分析
在不同数据容量,不同并发数,不同查询属性数的条件下进行多次测试并取平均值,所得到的数据分以下几种情况进行分析:
1、在deviceattr表数据容量为4000条,并发数分别为1、5、10、20、40、80,查询属性数分别为2、3、4、5、6的情况下,查询语句的耗时:
从上表可以看出,在查询属性数相同条件下,并发数增长一倍,耗时也基本增加一倍;在40并发数以下时,查询耗时不超过100毫秒;在10并发左右的实际应用情况下,耗时在40毫秒左右;性能基本满足新资源平台的要求。
2、在10并发,deviceattr表容量分别为3000、4000、8000条,查询属性数从2至6的情况下,查询语句的耗时:
从上表可以看出,在并发数一定的情况下,随着语句中查询属性数的增多,耗时线性增加,这种线性关系数据容量无关。
3、在10并发,查询属性数为5,不同数据容量的情况下,查询语句的耗时:
从上表可以看出,在其他条件一定的情况下,随着数据容量的增长,耗时呈线性增长,在贴近实际条件的情况下(4000左右数据容量,10左右并发数,5左右查询属性),耗时为25毫秒,满足新资源管理平台的需求。
附录:
生成测试数据的sql脚本:
use test1
drop table if exists device,attr,deviceattr;
drop function if exists rand_name;
drop function if exists rand_value;
drop function if exists rand_num;
drop function if exists rand_creator;
drop procedure if exists insert_devattr;
drop procedure if exists insert_dev;
create table device
(
id int primary key,
name varchar(40),
type varchar(40),
aquired int,
groupname varchar(40),
creator varchar(40)
);
create table attr
(
id int primary key,
name varchar(40)
);
create table deviceattr
(
id int,
name varchar(40),
value varchar(40)
);
delimiter //
create function rand_creator()
returns varchar(20)
begin
declare return_str varchar(20) default 'aronhe';
declare n int default 0;
set n = floor(rand()*10);
case n
when 0 then set return_str = 'aronhe';
when 1 then set return_str = 'eeelin';
when 2 then set return_str = 'shadowyang';
when 3 then set return_str = 'luzhao';
when 4 then set return_str = 'tommyzhang';
when 5 then set return_str = 'pillarzou';
when 6 then set return_str = 'allenpan';
when 7 then set return_str = 'beyondli';
when 8 then set return_str = 'minshi';
when 9 then set return_str = 'bingchen';
else set return_str = 'joyhu';
end case;
return return_str;
end//
create function rand_num()
returns int
begin
declare n int default 0;
set n = floor(rand()*100);
return n;
end//
create function rand_value()
returns varchar(10)
begin
declare return_str varchar(10) default 'false';
declare n int default 0;
set n = floor(rand()*10);
case
when n<5 then set return_str = 'false';
when n>5 then set return_str = 'true';
else set return_str = 'true';
end case;
return return_str;
end//
create function rand_name()
returns varchar(20)
begin
declare return_str varchar(20) default '';
set return_str = concat('attr',floor(rand()*200));
return return_str;
end//
create procedure insert_devattr(in start int,in max int)
begin
declare i int default 0;
repeat
set i=i+1;
insert into deviceattr values(rand_num(),rand_name(),rand_value());
until i =max
end repeat;
end//
create procedure insert_dev(in start int,in max int)
begin
declare i int default 10;
repeat
set i=i+1;
insert into device values(i,concat('runner',floor(rand()*100)),'pc',floor(rand()*2),'PCQQ',rand_creator());
until i =max
end repeat;
end//
call insert_devattr(0,4000)//
call insert_dev(11,100)//