运用Loadrunner测试Mysql数据库性能 TRON?极客

1.前言

针对数据库的性能测试,loadrunner本身支持sql server和oracle数据库,这两种数据库可以用loadrunner直接录制进行测试。而我们项目中使用的是mysql数据库,针对用 loadrunner测试mysql数据库的方法网上也有很多介绍文章,主要有两种方案。一种是利用ODBC连接测试mysql,但是这种方法配置比较麻 烦,如果要录制的话需要安装支持ODBC连接的查询分析器,这工具不好找,能找到的也只能算凑合能用。如果大家有兴趣试试这种方法,可以上网搜搜,学习配 置一下。另外一种方法是利用mysql lib库进行测试,这也是loadrunner推荐的测试方法,模拟mysql客户端连接数据库进行增删改查的操作进行测试,这种方法配置简单,不过不能 通过录制的方法得到测试脚本,需要一定的编程基础,手工编写测试脚本,当然,可以参考loadrunner的联机帮助+google进行。下面主要介绍第 二种方法,如何利用mysql lib库连接mysql数据库进行性能测试。

2.配置loadrunner连接使用mysql

Loadrunner不能直接跟mysql进行通信,在使用loadrunner之前需要将一些库文件和dll文件添加到loadrunner的安 装目录中。这些文件需要添加到所有需要执行测试脚本的系统中,包括需要使用loadrunner控制器,虚拟用户生成器和loadrunner代理的测试 负载机。

在附件中的MySQL LoadRunner libraries.zip中包含两个文件夹,bin和include。将这两个文件夹覆盖loadrunner安装目录中的bin和include两个 文件夹(将bin和include文件夹中的文件分别拷贝到loadrunner安装目录中对应的bin和include文件夹中也可以)。 Loadrunner安装目录通常是下面两种格式:

C:\Program Files (x86)\HP\LoadRunner(32位操作系统) 和 C:\Program Files\HP\LoadRunner(64位操作系统)

然后,在编写测试脚本时,就需要引用这些库文件了,具体操作如下:

  • 在loadrunner脚本中,需要将下面这行代码添加到vuser_init()这是初始化函数之前,这样做是为了让loadrunner在后续的操作中都能引用这些库文件。

   #include "Ptt_MySQL.h";

  • 还需要用一个函数来加载dll文件到内存中,将下面这行代码添加到需要进行连接数据库操作之前,这样才能让loadrunner连接到mysql数据库。

   lr_load_dll ("libmysql.dll");

  这行代码最好添加在vuser_init()函数中。

  • 我们还需要配置连接数据库的详细信息。
#define MYSQLSERVER "SERVER_NAME"
#define MYSQLUSERNAME "USER_NAME"
#define MYSQLPASSWORD "PASSWORD"
#define MYSQLDB "SCHEMA_NAME"
#define MYSQLPORT "PORT"

  用实际的mysql数据库连接信息替换引号中的参数值。

  • 现在,vuser_init()函数应该看起来像这个样子。

  

  到现在,已经做好了loadrunner连接数据库的准备,可以对mysql数据库进行增、删、改、查的操作了。

3.用loadrunner进行mysql数据库的查询操作

现在,我们可以在loadrunner脚本中插入任意的函数来进行连接并查询mysql数据库了。下面是一段示例,在Action()函数中如何进行连接mysql数据库并进行查询的操作。

//Declare MySQL Elements

char sqQuery[512]; // The MySQL query to be executed #定义一个字符数组存储查询的sql语句

MYSQL *Mconn; // The MySQL connection string #mysql连接字符串

int MyRC; // The MySQL return code #mysql的返回码,可以判断sql语句是否执行成功。

Action()

{

//Create the connection string to connect to the server and relevant database #创建一个连接字符串连接服务器和数据库

Mconn = lr_mysql_connect(MYSQLSERVER, MYSQLUSERNAME, MYSQLPASSWORD, MYSQLDB, atoi(MYSQLPORT));

//Build an SQL query and save the query as sqQuery #构建一个sql语句存储在sqQuery字符数组中

sprintf(sqQuery, "select username, password, secret from loadrunner_db.parameters");

//Execute the SQL query (sqQuery) against the server and database defined as Mconn #执行sql语句

lr_mysql_query(Mconn, sqQuery);

//Save the values returned in the first row of the table #查询的结果会存在一个表中,这里取出第一行的数据。

//N.B. The row/cell values appear to be the "wrong way round" #注意,这里的行和列是颠倒的,相当于返回的数据表中一列数据表示数据库中表的一行数据。

lr_save_string(row[0][0].cell, "sUsername");

lr_save_string(row[1][0].cell, "sPassword");

lr_save_string(row[2][0].cell, "sSecret");

//Output the returned values #打印出查询出来的结果

lr_output_message(lr_eval_string("Username: {sUsername}"));

lr_output_message(lr_eval_string("Password: {sPassword}"));

lr_output_message(lr_eval_string("Secret: {sSecret}"));

//Disconnect from MySQL #断开数据库连接

lr_mysql_disconnect(Mconn);

return 0;

}

提示:可以用lr_mysql_query函数执行任何sql语句,如果是执行的select操作,会有返回数据,返回的数据存储在一个多维数组中,可以用下面的语句将数据取出。

row[x][y].cell

注意,这里的行和列是颠倒的,x表示列(第一列是0),y表示行(第一行是0)。

4.用loadrunner进行mysql数据库的插入操作

插入操作,只需将sql语句换成插入的sql语句即可,其他操作根据实际情况更改。

下面是一段示例代码:

sprintf(sqQuery, "insert into loadrunner_db.results (id, username,password) values (‘1‘,‘tom‘,‘123456‘)";

这段语句是插入一条数据,但实际情况是,我们在测试时可能需要插入很多不同的数据,如果id是主键,用这条数据就会报错,因为主键不能重复。所以我们需要对插入的数据进行参数化,代码就需要改成:

sprintf(sqQuery, " insert into loadrunner_db.results (username,password) values(\"%s\",\"%s\")",lr_eval_string("{user}"),lr_eval_string("{pwd}"));

在数据库表中,如果id是主键,我们将id设置成自增长,让其每添加一条数据,id自动加1。

Sprintf函数的作用就是将字符串格式化后存入指定的变量中,那么我们可以将需要参数化的部分格式化处理,然后参数化输入的变量。%s表示格式 化成字符串,后面的lr_eval_string(“xxx”)是输入的参数,每一个参数对应一个%s,用逗号分隔参数,参数化输入的参数xxx,即变成 lr_eval_string(“{user}”),我们将需要输入的参数全部在user.dat文件中定义即可。

还有其他格式化表示为:%d,double型;%f,float型;%i,int型等等。

Update和delete的操作跟insert类似,参数化方法一样。

一个完成的示例:

//Declare MySQL Elements

char sqQuery[512];            // The MySQL query to be executed

MYSQL *Mconn;                 // The MySQL connection string

//Declare variables which can be sent to MySQL in this sample script

double dDuration;

int iMIN, iMAX, i, iRand;

Action()

{

lr_start_transaction("0001_Example");

lr_think_time(1);

dDuration=lr_get_transaction_duration("0001_Example");

lr_end_transaction("0001_Example",LR_AUTO);

lr_save_datetime("%H:%M:%S", TIME_NOW, "sTime");

iRand = fRandInt (1,1000000);

//Create the connection string to connect to the server and relevant database

Mconn = lr_mysql_connect(MYSQLSERVER, MYSQLUSERNAME, MYSQLPASSWORD, MYSQLDB, atoi(MYSQLPORT));    //Connect to the MySQL server defined in ..\..\LR_Includes\MySQLSettings.h

//Build an SQL query and save the query as sqQuery

sprintf(sqQuery, "insert into loadrunner_db.results (time, duration, returned_data)"

"values (\"%s\",\"%f\",\"%i\")",

lr_eval_string("{sTime}"),

dDuration,

iRand);
//Execute the SQL query (sqQuery) against the server and database defined as Mconn
lr_mysql_query(Mconn, sqQuery);

lr_output_message("This SQL statement executed - [%s]",sqQuery);

//Disconnect from MySQL

lr_mysql_disconnect(Mconn);

return 0;

}

5.如何进行性能测试

以上我们介绍了怎么利用loadrunner连接mysql数据库进行增删改查的操作,那么我们要对数据库进行性能测试该怎么操作呢,有了上面的方法,进行测试就好办多了。

首先,我们先确定测试目标。通过分别对数据库进行增、改、查的操作,测试出最大的并发操作数和最佳并发操作数,以及最大的执行速率和平均执行速率。 我们先定义一下,这里的并发操作,并非是同一时刻去操作数据库,而是建立多个连接进行数据库操作,并不一定在同一个时间点操作数据库,所以在脚本中就不设 置集合点了。

结合上面的例子,我们需要对脚本进行修改,设置事务以及判断事务是否成功。因为我们需要测试在进行增、改、查时的性能,所以我们将执行sql语句操 作设置在一个事务中。因为需要循环的操作,让每个连接处在活动的状态,为了不让频繁的连接、断开数据库,我们将连接数据库和关闭数据库的操作分别放在 vuser_init()和vuser_end()函数中,把执行增、改、查的操作放在Action()中,对于连接数据库的操作,我们还需要判断是否连 接成功,如果连接失败,做一个标记,在后续的操作中跳过失败的连接,否则会出现脚本错误,影响测试结果。判断连接数据库是否成功的脚本,可以直接将头文件 Ptt_MySql.h中的连接数据库的操作函数拷贝到vuser_init()中进行修改,添加一个事务来统计连接成功的次数。

完整脚本示例:

#include "typelib.h"

#include "my_list.h"

#include "my_alloc.h"

#define MYSQLSERVER "192.168.1.252"

#define MYSQLUSERNAME "root"

#define MYSQLPASSWORD "root"

#define MYSQLDB    "test"

#define MYSQLPORT "3306"

char chQuery[1024];

int statu=1;

int status=0;

MYSQL *Mconn;

char sql_query[256], sql_sub_query[50];

int i=0, res=0, conn_fail=0, conn_iter=0;

char response[50];// to go

vuser_init()

{

lr_load_dll("libmysql.dll");

//Mconn = lr_mysql_connect(MYSQLSERVER, MYSQLUSERNAME, MYSQLPASSWORD, MYSQLDB, atoi(MYSQLPORT));

lr_start_transaction("mysql_conn"); //设置一个连接数据库的事务

/*------------------------------------------------------------------------*/

/* Initialise MySQL */

if(!(Mconn = mysql_init(NULL)))

{

lr_message("Error -1: Cannot initialize MySQL - %s", mysql_error(Mconn));

//return -1;

statu = 0;

lr_end_transaction("mysql_conn", LR_FAIL); //初始化数据库失败判定事务失败

}

/*------------------------------------------------------------------------*/

do

{

/* Connect to database */

if (!mysql_real_connect(Mconn, MYSQLSERVER, MYSQLUSERNAME, MYSQLPASSWORD, MYSQLDB, atoi(MYSQLPORT), NULL, 0))

{

conn_fail = -2;

conn_iter++;

sleep(100);

}

else

conn_fail = 0;

}

while(conn_fail < 0 && conn_iter < 10);

if (conn_fail < 0)

{

lr_message("Error -2: %s", mysql_error(Mconn));

//mysql_close(Mconn);

//return -2;

statu = 0;

lr_end_transaction("mysql_conn", LR_FAIL); //连接数据库失败判定事务失败

}

else

{

//lr_message("MySql - Good Connection");

//mysql_close(Mconn);

statu = 1;

lr_end_transaction("mysql_conn", LR_PASS); //连接数据库成功,事务通过。

}

return 0;

}

Action()

{

if(statu){ //成功连接数据库后才进行执行sql的操作

lr_start_transaction("mysql_insert");

sprintf(chQuery, "INSERT INTO lr_test (username,password) VALUE(\"%s\",\"%s\")",lr_eval_string("{user}"),lr_eval_string("{pwd}"));

//sprintf(chQuery,"SELECT username,password FROM lr_test");

//sprintf(chQuery,"UPDATE lr_test SET password = \"%s\" WHERE username=‘tom‘",lr_eval_string ("{pwd}"));

status = lr_mysql_query(Mconn, chQuery);

if(status!=0){ //判断sql是否执行成功

lr_end_transaction("mysql_insert",LR_FAIL );

}else{

lr_end_transaction("mysql_insert", LR_PASS);

}

}

return 0;

}

vuser_end()

{

lr_mysql_disconnect(Mconn); //关闭数据库连接

return 0;

}

以上是插入数据的操作,根据之前的介绍, 测试更新和查询,只需修改sql语句即可。剩下的就是将脚本加载到负载生成器中,进行各种场景的配置、测试即可。

各种测试场景运行完之后,就是分析图表的过程了,因为我们测试是针对执行sql语句设置的事务,即通过一个事务就成功的执行一句sql语句,那么事 务的响应时间也就是执行sql所花的时间,可以取平均事务响应时间作为平均执行一句sql所花时间的度量。每秒事务数是在单位时间(秒)内执行sql的条 数,作为执行sql语句速率的度量。

在运行测试场景时,尽量将运行时间设置长一些,这样采集到的数据越多,结果越准确。分别模拟不同的虚拟用户数来测试,不同的虚拟用户数在运行场景 时,每秒事务数是不一样的,当达到一定的虚拟用户数后,每秒事务数会降低,或者出现错误,此时测试即可结束,取每秒事务数最大的一组数据作为测试结果。

以上就是loadrunner利用mysql lib库测试mysql数据库的一个大致过程。

6.参考资料

http://www.bish.co.uk/forum/index.php?topic=50.0

http://www.bish.co.uk/forum/index.php?topic=77.0

7.解决中文字符问题

解决方法:
在连接数据库前设置字符集
MYSQL *Mconn;
//设置字符集
mysql_options(Mconn, MYSQL_SET_CHARSET_NAME, "GBK");

时间: 2024-08-25 14:04:39

运用Loadrunner测试Mysql数据库性能 TRON?极客的相关文章

python测试mysql数据库性能(二)

一,普通写入数据库 二,批量写入数据库 三,普通写入数据库添加事务 config = { 'host': 'localhost', 'port': 3306, 'database': 'test', 'user': 'root', 'password': '1234qwer', 'charset': 'utf8' } conn = pymysql.connect(**config) cur = conn.cursor() def timer(fn): def _wrapper(count): s

mysql数据库性能参数配置(转)

max_connections MySql的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,MySql会为每个连接提供连接缓冲区,就会开销越多的内存,连接数太大,服务器消耗的内存越多,以至于影响服务器性能,所以要根据服务器的配置适当调整该值,不能盲目提高设值.可以过'conn%'通配符查看当前状态的连接数量,以定夺该值的大小. show variables like 'max_connections' 最大连接数

python测试mysql写入性能完整实例

这篇文章主要介绍了python测试mysql写入性能完整实例,具有一定借鉴价值,需要的朋友可以参考下 本文主要研究的是python测试mysql写入性能,分享了一则完整代码,具体介绍如下. 测试环境: (1) 阿里云服务器centos 6.5 (2) 2G内存 (3) 普通硬盘 (4) mysql 5.1.73 数据库存储引擎为 InnoDB (5) python 2.7 (6) 客户端模块 mysql.connector 测试方法: (1) 普通写入 (2) 批量写入 (3) 事务加批量写入

架构设计:系统存储(8)——MySQL数据库性能优化(4)

================================ (接上文<架构设计:系统存储(7)--MySQL数据库性能优化(3)>) 4-3.InnoDB中的锁 虽然锁机制是InnoDB引擎中为了保证事务性而自然存在的,在索引.表结构.配置参数一定的前提下,InnoDB引擎加锁过程是一样的,所以理论上来说也就不存在"锁机制能够提升性能"这样的说法.但如果技术人员不理解InnoDB中的锁机制或者混乱.错误的索引定义和同样混乱的SQL写操作语句共同作用,那么导致死锁出现的

架构设计:系统存储(9)——MySQL数据库性能优化(5)

=================================== (接上文<架构设计:系统存储(9)--MySQL数据库性能优化(5)>) 4-3-3-3.避免死锁的建议 上一篇文章我们主要介绍了MySQL数据库中锁的基本原理.工作过程和产生死锁的原因.通过上一篇文章的介绍,可以确定我们需要业务系统中尽可能避免死锁的出现.这里为各位读者介绍一些在InnoDB引擎使用过程中减少死锁的建议. 正确使用读操作语句 经过之前文章介绍,我们知道一般的快照读是不会给数据表任何锁的.那么这些快照读操作

sqoop测试Mysql数据库的使用

测试Mysql数据库的使用 前提:导入mysql jdbc的jar包 ①  测试数据库连接 sqoop list-databases–connect jdbc:mysql://192.168.10.63 –username root–password 123456 ②Sqoop的使用 以下所有的命令每行之后都存在一个空格,不要忘记 (以下6中命令都没有进行过成功测试) <1>mysql–>hdfs sqoop export –connect jdbc:mysql://192.168.10

MySQL 数据库性能优化之索引优化

这是 MySQL数据库性能优化专题 系列的第三篇文章:MySQL 数据库性能优化之索引优化 索引为什么能提高数据访问性能? 很多人只知道索引能够提高数据库的性能,但并不是特别了解其原理,其实我们可以用一个生活中的示例来理解. 我们让一位不太懂计算机的朋友去图书馆确认一本叫做<MySQL性能调优与架构设计>的书是否在藏,这样对他说:"请帮我借一本计算机类的数据库书籍,是属于 MySQL 数据库范畴的,叫做<MySQL性能调优与架构设计>".朋友会根据所属类别,前往

优化MySQL数据库性能的八大方法

本文探讨了提高MySQL 数据库性能的思路,并从8个方面给出了具体的解决方法. 1.选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小.例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了.同样的,如果可以的话,我们应该

mysql数据库性能优化(包括SQL,表结构,索引,缓存)

优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段.降低 CPU 计算除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了.order by, group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算).当我们的 IO 优化做到一定阶段之后