




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
LoadRunner测试SQL语句性能本次通过loadRunner录制SQLServer介绍一下如何测试一个sql语句或存储过程的执行性能。主要分如下几个步骤完成:第一步、测试准备第二步、配置ODBC数据源第三步、录制SQL语句在SqlServer查询分析器中的运行过程第四步、优化录制脚本,设置事务第五步、改变查询数量级查看SQL语句的性能第六步、在controller中运行脚本下面开始具体的介绍:测试准备阶段我们首先要确认测试数据库服务器:我们可以在本地安装SQLSERVER数据库服务端及客户端,也可以确定一台装好的SQLSERVER服务器。接下来,准备测试数据:对数据库测试时我们要考虑的不是SQL语句是否能够正确执行,而是在某数量级的情况下SQL语句的执行效率及数据库服务的运行情况,所以我们分别准备不同数量级的测试数据,即根据实际的业务情况预估数据库中的记录数,在本次讲解中我们不考虑业务逻辑也不考虑数据表之间的关系,我们只建立一张表,并向此表中加入不同数量级的数据,如分别加入1000条、10000条、50000条、100000条数据查看某SQL语句的执行效率。在查询分析器中运行如下脚本:--创建测试数据库createdatabaseloadrunner_test;useloadrunnertest--创建测试数据表createtabletest_table(usernamevarchar(50),sexint,ageint,addressvarchar(100),postint)--通过一段程序插入不同数量级的记录,具体的语法在这里就不多说了declare@iintset@i=0while@i<1000 /循环1000次,可以根据测试数据情况改变插入条数beginBEGINTRANT1insertintotest_table(username,sex,age,address,post)values(户瑞海'+cast(@iasvarchar),@i—1,@i+1,'北京市和平里'+cast(@iasvarchar)+'号',123456);IF@@ERROR<>0beginrollback;select@@errorendelsebegincommit;set@i= @i+1endend好了,执行完上述语句后,建立的数据表中已经有1000条记录了,下面进行第二步的操作,配置ODBC数据源,为了能让loadrunner能够通过ODBC协议连接到我们建立的SQLSERVER数据路,我们需要在本机上建立ODBC数据源,建立方法如下:控制面板一性能和维护一管理工具一数据源(ODBC)--添加,在列表中选择SQLSERVER点击完成,根据向导输入数据源名称,链接的服务器,下一步,输入链接数据库的用户名和密码,更改链接的数据库,完成ODBC的配置,如果配置正确的话,在最后一步点击“测试数据源”,会弹出测试成功的提示。配置好ODBC数据源后就要录制SQL语句在查询分析器中的执行过程了:1、打开loadrunner,选择ODBC协议2、 在startrecording中的勺applicationtype选择Win32application;programtorecord中录入SQLSERVER查询分析器的路径“..\安装目录\isqlw.exe”3、 开始录制,首先通过查询分析器登录SQLSERVER,在打开的查询分析器窗口中输入要测试的SQL语句口“select*fromtest_table;”4、 在查询分析器中执行该语句,执行完成后,结束录制好了,现在就可以看到loadrunner生成的脚本了(由于脚本过长,在这里就不粘贴了,有需要的朋友可以加我QQ,我把脚本发给你们),通过这些语句,我们可以看出,登录数据库的过程、执行SQL语句的过程。接下来,我们来优化脚本,我们分别为数据库登录部分和执行SQL语句的部分加一个事物,在增加一个double的变量获取事务执行时间,简单内容如下:Action(){doubletrans_time;/定义一个double型变量用来保存事务执行时间lr_start_transaction("sqserver_login");/设置登录事务的开始lrd_init(&InitInfo,DBTypeVersion); //初始化链接(下面的都是loadrunner生成的脚本了,大家可以通过帮助查到每个函数的意思)lrd_open_context(&Ctx1,LRD_DBTYPE_ODBC,0,0,0);lrd_db_option(Ctx1,0T_0DBC_0V_0DBC3,0,0);lrd_alloc_connection(&Con1,LRD_DBTYPE_ODBC,Ctx1,0/*Unused*/,0);trans_time=lr_get_transaction_duration("sqserver_login");//获得登录数据库的时间lr_output_message("sqserver_login事务耗时%f秒",trans_time);//输出该时间lr_end_transaction("sqserver_login",LR_AUTO);/结束登录事务lr_start_transaction("start_select");//开始查询事务lrd_cancel(0,Csr2,0/*Unused*/,0);lrd_stmt(Csr2,"select*fromtest_table;\r\n",-1,1,0/*None*/,0);//此句为执行的SQLlrd_bind_cols(Csr2,BCInfo_D42,0);lrdfetch(Csr2,-10, 1, 0,PrintRow24,0);trans_time=lr_get_transaction_duration("start_select");//获得该SQL的执行时间lr_output_message("start_select事务耗时%f秒",trans_time);//输出该时间lrendtransaction("startselect",LRAUTO);//结束查询事务优化后,在执行上述脚本后,就可以得到登录到数据库的时间及运行select*fromtest_table这条语句的时间了,当然我们也可以根据实际情况对该条语句进行参数化,可以测试多条语句的执行时间,也可以将该语句改为调用存储过程的语句来测试存储过程的运行时间。接下来把该脚本在controller中运行,设置虚拟用户数,设置集合点,这些操作我就不说了,但是值得注意的是,没有Mercury授权的SQLSERVER用户license,在运行该脚本时回扌报错,提示“YoudonothavealicenseforthisVusertype.PleasecontactMercuryInteractivetorenewyourlicense”我们公司穷啊买不起loadrunner,所以我也无法继续试验,希望有license朋友们监控一下运行结果!最起码在VUGen中运行该脚本我们可以得到任意一个SQL语句及存储过程的执行时间,如果我们测试的B/S结构的程序,我们也可以通过HTML协议录制的脚本在CONTROLLER中监控SQLSERVER服务器的性能情况,这样两方面结合起来就可以对数据库性能做一个完整的监控了。本人对LOADRUNNER也是在摸索中,如果文章有写的不对,或理解错误的地方请指出,不甚感激。(以上言论仅代表作者的个人观点,不代表51Testing观点)/*需要的表结构如下CREATETABLE'test_data'('order_id'BIGINTUNSIGNEDNOTNULLCOMMENT'Ordernumbers.Mustbeunique.','status'BOOLNOTNULLDEFAULT'O'COMMENT'Whetherdatahasbeenusedornot.Avalueof0meansFALSE.',、date_used'DATETIMENULLCOMMENT'Date/timethatthedatawasused.',UNIQUE('order_id'))ENGINE=innodbCOMMENT='LoadRunnertestdata';*/Action(){intrc;intdb_connection;//数据库连接intquery_result;//查询结果集MYSQL_RESchar**result_row;//查询的数据衕char*server="localhost";char*user="root";char*password="123456";char*database="test";intport=3306;intunix_socket=NULL;intflags=0;//找到libmysql.dll的所在位置.rc=lr_load_dll("C:\\ProgramFiles\\MySQL\\MySQLServer5.1WbinWlibmysql.dll");if(rc!=0){lr_error_message("Couldnotloadlibmysql.dll");lr_abort();}//创建MySQL对象db_connection=mysql_init(NULL);if(db_connection==NULL){lr_error_message("Insufficientmemory");lr_abort();}//连接到MySQL数据库rc=mysql_real_connect(db_connection,server,user,password,database,port,unix_socket,flags);if(rc==NULL){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}//向数据库插入数据//此处的{ORDER_ID}是一个参数,简单测试时可以用一个常数代替lr_save_string(lr_eval_string("INSERTINTOtest_data(order_id)VALUES({ORDER_ID})"),"paramInsertQuery");rc=mysql_query(db_connection,lr_eval_string("{paramInsertQuery}"));if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}//从数据库读取一个数据并显示rc=mysql_query(db_connection,"SELECTorder_idFROMtest_dataWHEREstatusISFALSELIMIT1");if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}query_result=mysql_use_result(db_connection);if(query_result==NULL){lr_error_message("%s",mysql_error(db_connection));mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}//如果结果集包含多行数据,需要多次调用mysql_fetch_row直到返回NULLresult_row=(char**)mysql_fetch_row(query_result);if(result_row==NULL){lr_error_message("Didnotexpecttheresultsettobeempty");mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}//保存参数,用于删除这行数据lr_save_string(result_row[O],"paramOrderlD");lr_output_message("OrderIDis:%s",lr_eval_string("{paramOrderID}"));mysql_free_result(query_result);//在事务里更新一行数据,需要用InnoDB引擎rc=mysql_query(db_connection,"BEGIN");//启动事务if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}//使用"FORUPDATE"锁住要更新的数据行rc=mysql_query(db_connection,"SELECTorder_idFROMtest_dataWHEREstatusISFALSELIMIT1FORUPDATE");if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}query_result=mysql_use_result(db_connection);if(query_result==NULL){lr_error_message("%s",mysql_error(db_connection));mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}result_row=(char**)mysql_fetch_row(query_result);if(result_row==NULL){lr_error_message("没有查询到结果");mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}lr_save_string(result_row[O],"paramOrderID");lr_output_message("OrderIDis:%s",lr_eval_string("{paramOrderID}"));mysql_free_result(query_result);lr_save_string(lr_eval_string("UPDATEtest_dataSETstatus=TRUE,date_used=NOW()WHEREorder_id='{paramOrderID}'"),"paramUpdateQuery");rc=mysql_query(db_connection,lr_eval_string("{paramUpdateQuery}"));if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}rc=mysql_query(db_connection,"COMMIT");//提交事务if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}//再次查找数据,应该为空了,因为前面的事务更新了标志rc=mysql_query(db_connection,"SELECTorder_idFROMtest_dataWHEREstatusISFALSELIMIT1");if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}query_result=mysql_use_result(db_connection);if(query_result==NULL){lr_error_message("%s",mysql_error(db_connection));mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}result_row=(char**)mysql_fetch_row(query_result);if(result_row==NULL){lr_output_message("Resultsetisemptyasexpected");mysql_free_result(query_result);}else{lr_error_message("Didnotexpecttheresultsettocontainanyrows");mysql_free_result(query_result);mysql_close(db_connection);lr_abort();}//删除数据lr_save_string(lr_eval_string("DELETEFROMtest_dataWHEREorder_id='{paramOrderID}'"),"paramDeleteQuery");rc=mysql_query(db_connection,lr_eval_string("{paramDeleteQuery}"));if(rc!=0){lr_error_message("%s",mysql_error(db_connection));mysql_close(db_connection);lr_abort();}//释放MySQL资源mysql_close(db_connection);return0;}本文章来源于西盟软件站【/r/】详细地址:/article/175/data/2009/2009070819880.html(转)LoadRunner测试过程中调用dll文件的制作与使用上一篇/下一篇2009-01-1716:35:36/个人分类:LoadRunner查看(109)/评论(0)/评分(0/0)在Windows操作系统中使用DLL有很多优点,最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件,真正实现了资源"共享”,大大缩小了应用程序的执行代码,更加有效的利用了内存;使用DLL的另一个优点是DLL文件作为一个单独的程序模块,封装性、独立性好,在软件需要升级的时候,开发人员只需要修改相应的DLL文件就可以了,而且,当DLL中的函数改变后,只要不是参数的改变,程序代码并不需要重新编译。这在编程时十分有用,大大提高了软件开发和维护的效率。在LR下也可以直接调用动态链接库文件,针对一些使用LR脚本编写比较烦琐的方法可以考虑此方法(比如各种加解密算法的实现,数据库的操作等),并能够使测试脚本简单明了。鉴于此,本人初次尝试了如何制作DLL文件并在LR中使用。1、dll文件的制作在VisualC++6.0开发环境下,打开File-New-Project选项,可以选择Win32Dynamic-LinkLibrary来创建一个名为dllfortest的空的dll工程(这只是方法之一)。在该项目中新建一个dllfortest.h和dllfortest.cpp文件,文件的内容如下://dllfortest.hextern"C"_declspec(dllexport)intMax(inta,intb,intc);extern"C"_declspec(dllexport)intMin(inta,intb,intc);//dllfortest.cpp包含一个计算三个整数中最大值和最小值的方法#include"dllfortest.h"intMax(inta,intb,intc)intRes;Res=(a>b?a:b)>c?(a>b?a:b):c;returnRes;}intMin(inta,intb,intc){intRes;Res=(a>b?b:a)>c?c:(a>b?b:a);returnRes;}该动态链接库编译成功后,打开dllfortest工程目录下的debug目录下,可以看到生成了一个dllfortest.dll文件,这就是我们想要的文件。2、dll文件在LR中的调用打开LRVUGenerator,选择CVuser协议(或其他支持C的协议),进入编辑界面。Action部分如下所示:Action(){lr_load_dll("dllfortest.dll");lr_message("MaxResultis%d",Max(100,200,67));lr_message("MinResultis%d",Min(55,97,63));return0;}将dllfortest.dll文件复制到脚本所在的目录(如果不复制的话,lr_load_dll的参数应该写成dll文件的绝对路径),如果编译没有报错的话,就可以直接运行了。运行结果如下:VirtualUserscrptstartedStartingactionvuser_init.Endingactionvuser_init.RunningVuser...Startingiteration1.StartingactionAction.MaxResultis200MinResultis55EndingactionAction.Endingiteration1.EndingVuser...Startingactionvuser_end.Endingactionvuser_end.VuserTerminated.如果在脚本中用到了DLL文件中并不存在的方法名时,编译也能通过,但是运行时LR会报错,提示不存在该方法比如我们在脚本中添加一句:lr_message("MinResultis%d",Sum(55,97,63));//Sum方法并不存在运行时错误信息如下:Action.c(7):Error:Cinterpreterruntimeerror:Action.c(7):Error--Unresolvedsymbol:Sum.Action.c(7):Notify:CCItrace:Compiled_code(0):Action()这个例子并没有体现出DLL文件调用的优点,因为调用的方法在LR中用C直接就可以完成,但涉及到LR中完不成的任务时,或许dll文件的作用就体现出来了example:LoadRunner提供了功能强大的API集合,足够应付大多数性能测试的需求。但在某些情况下,这些API仍然有覆盖不到的地方。例如,我们有一个WEB应用,该应用有一个页面输入用户的信息,为了安全起见,用户输入的信息在提交之前都要先进行加密处理,加密处理通过本地的COM组件实现。对这个要求而言,LoadRunner的现有API不能提供直接支持,因为LoadRunner在录制脚本时只录制数据交互,因此,COM的加密处理过程是不能录制下来的。在LoadRunner的脚本中,可能只有类似以下的语句描述了这个过程:web_url("userinfo","URL=http://testweb/userinfo.aspx","TargetFrame=","Resource=0","Referer=",LAST);web_submit_form("login","Snapshot=t4.inf",ITEMDATA,"Name=username","Value=4e92Sh6d394g",ENDITEM,"Name=password","Value=932A2hf34U18",ENDITEM,LAST);从脚本可以看到,输入的数据是加密后的数据,但LR没有录制到加密过程。假设加密函数所在的DLL名为security.dll,用于加密的函数名为encode,则一种可能的对脚本的修改方法如下代码所示。char*encode_username,*encode_password,*orgin_username,*orgin_password;char*uservalue,passvalue;intret;web_url("userinfo","URL=http://testweb/userinfo.aspx","TargetFrame=","Resource=0","Referer=",LAST);orgin_username=lr_eval_string(“{username}”);〃获取参数的值orgin_password=lr_eval_string(“{password}”);ret=lr_load_dll(“security.dll”); 〃加载DLL库encode(origin_username,encode_username);〃调用encode函数encode(origin_password,encode_password);sprintf(uservalue,“Value=%s”,encode_username);sprintf(passvalue,“value=%s”,encode_password);web_submit_form("login","Snapshot=t4.inf",ITEMDATA,"Name=username",uservalue,ENDITEM,"Name=password",passvalue,ENDITEM,LAST);注意:有些脚本录制需要相应的patch的支持,如录制DotNet编写的应用程序你需要把lr78安装盘\Patches\Trap_for_.net_patch文件夹中trpfnc32.32dll拷贝到loadrunner'bin路径下,才能正常工作。[转贴]LoadRunner下DLL的调用场景介绍最近在做类似于QQ的通信工具的性能测试时发现了一些问题,现总结出来与大家分享一下。希望大家在使用LoadRunner时不仅仅停在只是录制/播放脚本,而全面提升脚本的编程技术,解决复杂场景。本次测试中碰到的问题是这样的,在消息的传送过程中遇到了DEC加密的过程,LoadRunner录制到的全是加密的消息,比如我录制了某一个用户的登陆,发送消息,退出,但由于是加密的,只能单个用户使用,但如果我想并发多少个用户就存在很多问题,最直接的一个问题就是用户名是加密的,密码是加密的,当然你可以说让程序那里注掉加密的代码进行明码的测试,当然也是一种办法。但程序组提出了要使用更真实的方法来模拟,这时就必需使用下面介绍的方法。一开始是直接把API移植到LoadRunner中来,不过由于加密算法异常复杂,有几层循环,而脚本是解释执行的,进行一次加密运算可能需要好几分钟,当然在脚本里可以把脚本本身运行的时间去掉,但这样做显然没有直接调用DLL来的效率高。由于程序组比较忙,所以无法提供DLL给测试,所以测试组完成了DLL的编写,并在LoadRunner中调用成功,高效的完成了用户信息加密,参数关联,成功的完成了测试。动态链接库的编写在VisualC++6.0开发环境下,打开FileNewProject选项,可以选择Win32DynamicLinkLibrary建立一个空的DLL工程。Win32Dynamic-LinkLibrary方式创建Non-MFCDLL动态链接库每一个DLL必须有一个入口点,这就象我们用C编写的应用程序一样,必须有一个WINMAIN函数一样。在Non-MFCDLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的DLL需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的DLL工程的.CPP文件中对DIIMain()函数按照下面的格式书写。BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_reason_for_call丄PVOIDIpReserved){switch(ul_reason_for_call){caseDLL_PROCESS_ATTACH:break;caseDLL_THREAD_ATTACH:break;caseDLL_THREAD_DETACH:break;caseDLL_PROCESS_DETACH:break;default:break;}returnTRUE;}参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH:进程被调用、DLL_THREAD_ATTACH:线程被调用、DLL_PROCESS_DETACH:进程被停止、DLL_THREAD_DETACH:线程被停止;IpReserved为保留参数。到此为止,DLL的入口函数已经写了,剩下部分的实现也不难,你可以在DLL工程中加入你所想要输出的函数或变量了。我们已经知道DLL是包含若干个函数的库文件,应用程序使用DLL中的函数之前,应该先导出这些函数,以便供给应用程序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字_declspec(dllexport),另外一种方法是在创建DLL文件时使用模块定义文件.Def。需要读者注意的是在使用第一种方法的时候,不能使用DEF文件。下面通过两个例子来说明如何使用这两种方法创建DLL文件。1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码://MyDLL.hextern"C"_declspec(dllexport)intdesinit(intmode);extern"C"_declspec(dllexport)voiddesdone(void);extern"C"_declspec(dllexport)voiddes_setkey(char*subkey,char*key);extern"C"_declspec(dllexport)voidendes(char*block,char*subkey);extern"C"_declspec(dllexport)voiddedes(char*block,char*subkey);//MyDll.cpp
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 招教师考试试题及答案
- 素材收集的数学试题及答案示例
- 家具行业设计师所需的法律知识考题及答案
- 碘伏考试题及答案
- 新能源汽车行业的营销渠道研究试题及答案
- 梅州二模试题及答案政治
- 数学基础强化练习试题及答案幼儿园
- 探讨创业环境与扶持政策的互动性试题及答案
- 施工现场消防防护管理试题及答案
- 文化遗产数字化展示策略报告-2025年文化遗产数字化展示与传播技术创新研究
- 【MOOC】人工智能导论-福建师范大学 中国大学慕课MOOC答案
- 六年级数学分数混合运算练习300题及答案
- 儿童口腔舒适化治疗
- 《基金的信息披露》课件
- 2024年研发部规划
- 《冠心病》课件(完整版)
- 失业保险待遇申领表
- 销售提成及职能部门员工利润分红方案
- 药用植物学智慧树知到答案2024年浙江中医药大学
- 评职称业绩合同协议书
- 四年级《爷爷的爷爷从哪里来》阅读测评题
评论
0/150
提交评论