当前位置: 首页 > 测试知识 > 用LoadRunner进行数据库性能测试:ODBC与Oracle协议实操
用LoadRunner进行数据库性能测试:ODBC与Oracle协议实操
2026-07-27 作者cwb 浏览次数27

使用 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名称和参数绑定方式。


文章标签: 软件测试 测试工具
咨询软件测试