使用 LoadRunner 进行数据库性能测试是模拟大量虚拟用户并发执行SQL,以测量数据库的吞吐量、响应时间和资源消耗。ODBC和Oracle 2‑Tier是两种最常用的协议
一、环境准备
不管使用哪种协议,都要先装好必要的驱动,并准备一个测试库(如 Oracle 的 SCOTT 或 HR 样例用户)。
ODBC 协议需要:
对应数据库的 ODBC 驱动(如 Oracle 的 Instant Client + ODBC 包)。
LoadRunner VuGen 和 Controller。
Oracle 2‑Tier 协议需要:
完整的 Oracle Client(含 OCI 接口),并正确配置 tnsnames.ora 文件。
LoadRunner VuGen 和 Controller。
测试账号统一使用 scott/tiger。
Oracle 客户端配置示例:
安装 Oracle 客户端后,在 $ORACLE_HOME/network/admin/tnsnames.ora 中添加:
text
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.100)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
测试连通性:执行 tnsping ORCL,并通过 SQL*Plus 登录证实。
二、ODBC协议实操(连接 Oracle 示例)
1. 创建 ODBC 数据源
打开 Windows ODBC 数据源管理器(32 位或 64 位需和 LoadRunner 一致)。
在系统 DSN页添加一个Oracle驱动(如 Oracle in OraClient12Home1)。
填写 Data Source Name:ORA_ODBC,TNS Service Name:ORCL,User ID:scott。
测试连接成功。
2. VuGen 脚本开发
新建单协议脚本 - 选择 ODBC,进入代码视图编写脚本。
vuser_init.c
c
#include "lrd.h"
static LRD_INIT_INFO InitInfo = {LRD_INIT_INFO_EYECAT};
static LRD_DEFAULT_DB_VERSION_INFO DBVersionInfo = {
LRD_DB_VERSION_INFO_EYECAT, /* Header */
0, /* Dummy1 */
LRD_DBTYPE_ODBC, /* DB Type */
0, /* Dummy3 */
NULL, /* Dummy4 */
NULL /* Dummy5 */
};
void vuser_init()
{
lrd_init(&InitInfo, &DBVersionInfo);
lrd_db_connect(
LRD_DB_TYPE_ODBC,
"DSN=ORA_ODBC;UID=scott;PWD=tiger;",
"",
NULL,
0,
0
);
lr_output_message("ODBC connection established.");
return 0;
}
Action.c
c
#include "lrd.h"
void Action()
{
void * csr;
int rows_fetched = 0;
char ename[20];
double sal;
lr_start_transaction("ODBC_Query");
lrd_open_cursor(&csr, 0, 0);
lrd_exec(csr,
"SELECT ename, sal FROM emp WHERE deptno = 10",
LRD_EXEC_DEFAULT, 0, 0, 0
);
lrd_bind_col(csr, 1, ename, 20, 0);
lrd_bind_col(csr, 2, &sal, sizeof(double), 0);
while (lrd_fetch(csr, LRD_NEXT_ROW, 0, 0) != LRD_NO_MORE_ROWS) {
rows_fetched++;
lr_output_message("Employee: %s, Salary: %.2f", ename, sal);
}
lrd_close_cursor(csr, 0);
lr_end_transaction("ODBC_Query", LR_AUTO);
lr_output_message("Rows fetched: %d", rows_fetched);
return 0;
}
vuser_end.c
c
#include "lrd.h"
void vuser_end()
{
lrd_db_disconnect(0, 0, 0);
lr_output_message("ODBC connection closed.");
return 0;
}
3. 参数化和绑定变量
如果需使用参数,用占位符 ? 配合 lrd_assign_odbc_param:
c
lrd_open_cursor(&csr, 0, 0);
lrd_exec(csr, "SELECT ename, sal FROM emp WHERE deptno = ?", LRD_EXEC_DEFAULT, 0, 0, 0);
int dept = atoi(lr_eval_string("{DeptNoParam}"));
lrd_assign_odbc_param(csr, 1, LRD_DBTYPE_INT, &dept, sizeof(int), 0);
lrd_bind_col(csr, 1, ename, 20, 0);
lrd_bind_col(csr, 2, &sal, sizeof(double), 0);
// 之后正常 fetch
4. 运行时设置建议
Pacing:每次迭代间隔 1~3 秒。
Log:调试时打开扩展日志,压测时关闭。
Think Time:在 SQL 之间加入 lr_think_time(0.5) 模拟延迟。
多用户执行时每个 Vuser 默认在 vuser_init 建立一个连接。
三、Oracle 2‑Tier协议实操
直接调用OCI接口,无需ODBC,效率更高,且完整支持数组提取、PL/SQL 绑定等高级特性。
1. VuGen 脚本开发
新建脚本选择 Oracle - 2 Tier 协议。
vuser_init.c
c
#include "lrd.h"
static LRD_INIT_INFO InitInfo = {LRD_INIT_INFO_EYECAT};
static LRD_DEFAULT_DB_VERSION_INFO DBVersionInfo = {
LRD_DB_VERSION_INFO_EYECAT,
0,
LRD_DBTYPE_ORACLE,
0,
NULL,
NULL
};
static void * lr_conn;
void vuser_init()
{
lrd_init(&InitInfo, &DBVersionInfo);
lrd_ora8_dbConnect(
&lr_conn,
"ORCL",
"scott",
"tiger",
NULL,
0,
0
);
lr_output_message("Oracle connection established.");
return 0;
}
Action.c
c
#include "lrd.h"
extern void * lr_conn;
void Action()
{
void * csr;
int eno;
char ename[20];
double sal;
lr_start_transaction("Oracle_Query");
lrd_ora8_stmt(&csr, lr_conn,
"SELECT empno, ename, sal FROM emp WHERE deptno = :dept",
LRD_ORA8_STMT_DEFAULT,
0, 0, 0
);
int dept_val = 10;
lrd_ora8_bind_placeholder(csr, "dept", &dept_val, sizeof(int), 0);
lrd_ora8_define_placeholder(csr, "1", &eno, sizeof(int), 0);
lrd_ora8_define_placeholder(csr, "2", ename, 20, 0);
lrd_ora8_define_placeholder(csr, "3", &sal, sizeof(double), 0);
lrd_ora8_exec(csr, LRD_ORA8_EXEC_DEFAULT, 1, 0, 0);
int rows;
while (lrd_ora8_fetch(csr, LRD_ORA8_FETCH_NEXT, 10, &rows, 0) != LRD_NO_MORE_ROWS) {
for (int i = 0; i < rows; i++) {
lr_output_message("Empno=%d, Ename=%s, Sal=%.2f", eno, ename, sal);
}
}
lrd_ora8_stmt_close(csr, 0);
lr_end_transaction("Oracle_Query", LR_AUTO);
return 0;
}
vuser_end.c
c
#include "lrd.h"
extern void * lr_conn;
void vuser_end()
{
lrd_ora8_dbDisconnect(lr_conn, 0, 0);
lr_output_message("Oracle connection closed.");
return 0;
}
2. 高级参数化:数组 DML 示例
如果需批量插入数据,可使用数组绑定:
c
lrd_ora8_stmt(&csr, lr_conn,
"INSERT INTO bonus(ename, job, sal) VALUES(:1, :2, :3)",
LRD_ORA8_STMT_DEFAULT, 0, 0, 0);
char enames[100][20];
char jobs[100][20];
double sals[100];
int rows_to_insert = 100;
// 填充数组... (略)
lrd_ora8_bind_placeholder_arr(csr, "1", enames[0], 20, rows_to_insert, 0);
lrd_ora8_bind_placeholder_arr(csr, "2", jobs[0], 20, rows_to_insert, 0);
lrd_ora8_bind_placeholder_arr(csr, "3", sals, sizeof(double), rows_to_insert, 0);
lrd_ora8_exec(csr, LRD_ORA8_EXEC_DEFAULT, rows_to_insert, 0, 0);
lrd_ora8_commit(lr_conn, 0, 0);
3. 运行时设置
迭代计数:在 Run Logic 中设置多次迭代循环执行 Action。
检查点:一般直接通过事务时间测量,也可用 lr_db_getValue 证实。
连接管理:每个 Vuser 在 init 中建立一个物理连接,保证数据库 session 数充足。
四、数据库监控
在 Controller 中可添加服务器监控,实时采集 Oracle 重点计数器。
操作步骤:
在Controller的Run选项卡中,右键添加度量 - 选择 Oracle。
输入数据库服务器 IP,使用具有 SELECT ANY DICTIONARY 权限的账号(如 SYSTEM)登录。
选择计数器:
Session Count (当前会话数)
CPU used by this session (CPU 使用率)
Physical reads / writes (物理读写)
Parse Count (hard) (硬分析次数)
User calls / Execute count 等
这些标准能帮助你发现连接泄漏、分析风暴和 I/O 短板。对于 ODBC 连接 Oracle 的场景,监控方法完全相同,因为后端仍是同一个数据库。
五、常见问题和排错
问题: 录制或回放时报 Cannot load LRD library
原因: 未正确包含头文件或所选协议错误。
解决方案: 保证脚本使用单协议 ODBC/Oracle,必要时重装 VuGen 的数据库组件。
问题: lrd_db_connect 失败,返回 -1
原因: ODBC 数据源名错误、驱动不一致或 32/64 位不一致。
解决方案: 检查系统 DSN 是不是存在且驱动版本和 VuGen 位数一致。
问题: lrd_ora8_dbConnect 返回 12154
原因: TNS 无法分析服务名。
解决方案: 确定 tnsnames.ora 途径正确,或在连接串中直接写入完整描述字符串。
问题: 取数时数据错乱或截断
原因: 绑定列缓冲区长度不足或数据类型不一致。
解决方案: 增大缓冲区,保证 C 类型和数据库字段类型严格对应。
问题: 负载增大后 LR 报“无法创建连接”
原因: 数据库 sessions 或 processes 参数耗尽。
解决方案: 调大数据库的会话/进程数限制,或优化脚本减少连接占用时间。
六、协议选型对比
驱动依赖:
ODBC 协议:需要 Oracle ODBC 驱动。
Oracle 2‑Tier 协议:需要 Oracle Client (OCI)。
协议层数:
ODBC:应用 - ODBC 驱动 - OCI - 网络,多一层转换。
Oracle 2‑Tier:应用 - OCI - 网络,更直接。
性能开销:
ODBC 协议略高,Oracle 2‑Tier 协议更低,更接近原生。
可移植性:
ODBC 协议可连接任何提供 ODBC 驱动的数据库。
Oracle 2‑Tier 协议仅限 Oracle。
高级特性:
ODBC 协议支持参数绑定,但数组 DML 支持较弱。
Oracle 2‑Tier 协议完整支持 PL/SQL、数组绑定、批量 fetch。
维护难度:
ODBC 协议需额外维护 DSN。
Oracle 2‑Tier 协议只需维护 tnsnames.ora。
适用场景:
ODBC 协议适用于测试通过 ODBC 访问数据库的业务系统,或多数据库环境。
Oracle 2‑Tier 协议适用于直接测试Oracle数据库极限性能,或模拟OCI应用程序。
选型建议: 如果被测系统本身就是Oracle,且重视极限TPS,优先选择Oracle 2‑Tier;如果需证实ODBC中间件的性能,或数据库类型可能变化,则用ODBC协议。
通过以上实操,可以快速建立起数据库性能测试脚本,模拟并发查询和事务处理,并实时监控数据库运行状态。两个协议的重要思路一致:初始化 - 执行SQL - 取结果 - 关闭,区别仅是API名称和参数绑定方式。