---
title: "在 OceanBase 上进行 TPC-C 测试 | OceanBase 文档中心"
description: 在 OceanBase 上进行 TPC-C 测试 TPC-C 是 TPC 组织（Transaction Processing Performance Council）推出的一系列性能测试标准中的一款，自推出以来，一直是数据库业界性能测试的重要参考，全世界各大数据库厂商都向 TPC 委员会提交了测试结果，以期望在 TP…
image: https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*OSPzQ6GUQF4AAAAAQHAAAAgAeiGDAQ/original
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 3.1.4 社区版

# 在 OceanBase 上进行 TPC-C 测试

更新时间：2023-08-03 17:20:32

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V3.1.4/zh-CN/100.users-guide/200.Get-started-quickly/300.Experience-the-advanced-features-of-OceanBase/100.Experience-Scalable-OLTP/100.TPC-C-test-on-OceanBase.md)  

TPC-C 是 TPC 组织（Transaction Processing Performance Council）推出的一系列性能测试标准中的一款，自推出以来，一直是数据库业界性能测试的重要参考，全世界各大数据库厂商都向 TPC 委员会提交了测试结果，以期望在 TPC-C 测试的排行榜上取得更好的成绩。OceanBase 在 2019 年和 2020 年两次刷新了 TPC-C 的世界纪录，成为榜单上首个分布式关系型数据库。

在本篇文章中，通过在 OceanBase 上运行 TPC-C 测试的方式，体验 OceanBase 的 OLTP 能力。

## 关于 TPC-C

### 数据库模型

TPC-C Benchmark 规定了数据库的初始状态，其中 ITEM 表中包含固定的 10 万种商品，而仓库的数量可根据测试规模进行调整，假设 WAREHOUSE 表中有 W 条记录，那么：

- STOCK 表中应有 W×10 万条记录（每个仓库对应 10 万种商品的库存数据）；
 - DISTRICT 表中应有 W×10 条记录（每个仓库为 10 个地区提供服务）；
 - CUSTOMER 表中应有 W×10×3000 条记录（每个地区有 3000 个客户）；
 - HISTORY 表中应有 W×10×3000 条记录（每个客户一条交易历史）；
 - ORDER 表中应有 W×10×3000 条记录（每个地区 3000 个订单），并且最后生成的 900 个订单将被添加到 NEW-ORDER 表中，每个订单随机生成 5~15 条 ORDER-LINE 记录。

在测试过程中，每一个地区（DISTRICT）都有一个对应的终端（Terminal），模拟为用户提供服务。在每个终端的生命周期内，要循环往复地执行各类事务，当终端执行完一个事务的周期后，就进入下一个事务的周期。 客户下单后，包含若干个订单明细（ORDER-LINE）的订单（ORDER）被生成，并被加入新订单（NEW-ORDER）列表。 客户支付订单会产生交易历史（HISTORY）。 每个订单（ORDER）平均包含 10 条订单项（ORDER-LINE），其中 1% 需要从远程仓库中获取，这些就是 TPC-C 模型中的 9 个数据表。

### 事务类型

该 benchmark 包含 5 类事务：

- NewOrder：新订单请求从某一仓库中随机选取 5 ~ 15 件商品，创建新订单。其中 1% 的事务需要回滚（即 err）。一般地，新订单请求不可能超出全部事务请求的 45% 。
 - Payment：订单付款更新客户账户余额，反映其支付情况。在全部事务请求中占比 43% 。
 - OrderStatus：最近订单查询随机选择一个用户，查询其最近一条订单，显示该订单内的每个商品状态。在全部事务请求中占比 4% 。
 - Delivery：配送模拟批处理交易，更新该订单用户的余额，把发货单从 NewOrder 中删除。在全部事务请求中占比 4% 。
 - StockLevel：库存缺货状态分析，在全部事务请求中占比 4% 。

## 环境准备

### OceanBase 集群

根据部署的 OceanBase 集群类型不同，可以以不同的方式观察 OceanBase 的表现，如果是按照快速开始章节中创建的单节点 OceanBase 集群，那么本文中可以看到 OceanBase 在单机形态下的运行情况。如果希望体验 OceanBase 分布式架构的 scalable OLTP 能力，那么建议采用至少三节点的 OceanBase 集群进行测试。部署步骤可详见[安装部署](https://www.oceanbase.com/docs/community-observer-cn-1000000000051251)。 不论是哪类部署，此次 TPC-C 测试建议您通过 OceanBase 的分布式代理组件 ODP 连接，ODP 的默认端口为2883。 安装 ODP 的命令如下

```sql
yum install obproxy-ce-3.2.3-2.el7.x86_64.rpm

```

也可以通过 OBD 来部署 ODP ，具体可参考 [创建 OBProxy 集群](https://www.oceanbase.com/docs/community-observer-cn-10000000000450656) 本例中使用的租户名为 test，您可以创建自己的租户，具体步骤详见[【体验多租户特性】](https://www.oceanbase.com/docs/community-observer-cn-0000000000745133)

### 安装 BenchmarkSQL

TPC 组织为 TPC-C 定义了严格、详细的测试标准，一般情况下开发者如果想要模拟 TPC-C 的场景进行测试，可以使用目前常用的开源测试工具。例如本文中使用的 BenchmarkSQL 。 BenchmarkSQL 的官方下载地址为：[https://sourceforge.net/projects/benchmarksql/](https://sourceforge.net/projects/benchmarksql/)。 为了节省测试环境的准备时间，OceanBase 对原程序进行了修改，优化提升了测试数据加载的效率，可通过以下链接下载[https://github.com/obpilot/benchmarksql-5.0](https://github.com/obpilot/benchmarksql-5.0)

> **注意**
>
>  
>
> 测试环境需要有 Java 运行环境，且版本不低于 V1.8.0。

### 修改配置文件

配置文件 `props.ob` 在 BenchmarkSQL 的 `run/` 目录下

```test
db=oceanbase
driver=com.mysql.jdbc.Driver
conn=jdbc:mysql://127.0.0.1:2883/tpccdb?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&allowMultiQueries=true
user=root@test
password=******

warehouses=10
loadWorkers=2
//fileLocation=/data/temp/

terminals=10
//To run specified transactions per terminal- runMins must equal zero
runTxnsPerTerminal=0
//To run for specified minutes- runTxnsPerTerminal must equal zero
runMins=10
//Number of total transactions per minute
limitTxnsPerMin=0

//Set to true to run in 4.x compatible mode. Set to false to use the
//entire configured database evenly.
terminalWarehouseFixed=true

//The following five values must add up to 100
newOrderWeight=45
paymentWeight=43
orderStatusWeight=4
deliveryWeight=4
stockLevelWeight=4

// Directory name to create for collecting detailed result data.
// Comment this out to suppress.
resultDirectory=my_result_%tY-%tm-%td_%tH%tM%tS
osCollectorScript=./misc/os_collector_linux.py
osCollectorInterval=1
//osCollectorSSHAddr=user@dbhost
//osCollectorDevices=net_eth0 blk_sda

//LoadStartW=1
//LoadStopW=1000

```

> **说明**
>
>  
>
> - db：指定数据库类型。此处保持和模板一致即可
>  - driver：驱动程序文件，推荐使用 MySQL 的 JDBC 驱动：`mysql-connector-java-5.1.47`，[驱动下载地址](https://downloads.mysql.com/archives/c-j/)。
>  - conn：此处的 IP 建议填写 OceanBase server 的 IP，并且部署 OBProxy 通过 2883 端口访问，其他部分保持和模板一致。
>  - user & password ：根据环境中使用的用户名，租户名，以及密码即可。如果环境中有多个 OceanBase 集群，则 user 的格式建议为 {user_name}@{tenant_name}#{cluster_name}。
>  - warehouses：指定仓库数。仓库数决定性能测试的成绩。如果希望针对多节点的 OceanBase 集群进行测试，建议选择 1000 仓以上。如果机器配置有限，可以选择 100 仓进行测试。
>  - loadWorkers：指定仓库数据加载时的并发。如果机器配置较高，该值可以设置大一些，例如 100 。 如果机器配置有限，该值需要设置小一些，如 10 并发。过高的并发可能会导致内存消耗太快，出现报错，导致数据加载需要重新进行。
>  - terminals：指定性能压测时的并发数。建议并发数不要高于仓库数 * 10。否则，会有不必要的锁等待。在生产环境中，建议将此参数设置为最多 1000。在测试环境中，建议从 100 开始。
>  - runMins：指定性能测试持续的时间。时间越久，越能考验数据库的性能和稳定性。建议不要少于 10 分钟，生产环境中机器建议不少于 1 小时。
>  - LoadStartW 和 LoadStopW：指定补仓时的开始值和截止值。如果导数据时发现某个仓库数据导入失败。例如：大事务超时，可以指定这个仓库重新导入。

## 数据准备

### 创建 tpccdb 数据库

在测试租户 test 中，创建本次测试的数据库 tpccdb

```sql
create database tpccdb;

```

### 创建表

建表脚本通常放在 benchmarskSQL 的 run/sql.common 下或者其他指定目录下。建表脚本如下，采用分区表方式创建，大部分表按照仓库 ID 做 HASH 分区。分区数取决于要测试的数据规模和机器数。 如果集群只有 1 台或 3 台机器，分区数设置 9 个即可。如果是 5000 仓以上，或者集群中节点数较多，则分区数可以调整到 99。

```sql
[root@obce-0000 run]# cat sql.common/tableCreates_parts.sql
create table bmsql_config (
cfg_name    varchar(30) primary key,
cfg_value   varchar(50)
);

-- drop tablegroup tpcc_group;
create tablegroup tpcc_group partition by hash partitions 9;

create table bmsql_warehouse (
w_id        integer   not null,
w_ytd       decimal(12,2),
w_tax       decimal(4,4),
w_name      varchar(10),
w_street_1  varchar(20),
w_street_2  varchar(20),
w_city      varchar(20),
w_state     char(2),
w_zip       char(9),
primary key(w_id)
)tablegroup='tpcc_group' partition by hash(w_id) partitions 9;

create table bmsql_district (
d_w_id       integer       not null,
d_id         integer       not null,
d_ytd        decimal(12,2),
d_tax        decimal(4,4),
d_next_o_id  integer,
d_name       varchar(10),
d_street_1   varchar(20),
d_street_2   varchar(20),
d_city       varchar(20),
d_state      char(2),
d_zip        char(9),
PRIMARY KEY (d_w_id, d_id)
)tablegroup='tpcc_group' partition by hash(d_w_id) partitions 9;

create table bmsql_customer (
c_w_id         integer        not null,
c_d_id         integer        not null,
c_id           integer        not null,
c_discount     decimal(4,4),
c_credit       char(2),
c_last         varchar(16),
c_first        varchar(16),
c_credit_lim   decimal(12,2),
c_balance      decimal(12,2),
c_ytd_payment  decimal(12,2),
c_payment_cnt  integer,
c_delivery_cnt integer,
c_street_1     varchar(20),
c_street_2     varchar(20),
c_city         varchar(20),
c_state        char(2),
c_zip          char(9),
c_phone        char(16),
c_since        timestamp,
c_middle       char(2),
c_data         varchar(500),
PRIMARY KEY (c_w_id, c_d_id, c_id)
)tablegroup='tpcc_group' partition by hash(c_w_id) partitions 9;

create table bmsql_history (
hist_id  integer,
h_c_id   integer,
h_c_d_id integer,
h_c_w_id integer,
h_d_id   integer,
h_w_id   integer,
h_date   timestamp,
h_amount decimal(6,2),
h_data   varchar(24)
)tablegroup='tpcc_group' partition by hash(h_w_id) partitions 9;

create table bmsql_new_order (
no_w_id  integer   not null ,
no_d_id  integer   not null,
no_o_id  integer   not null,
PRIMARY KEY (no_w_id, no_d_id, no_o_id)
)tablegroup='tpcc_group' partition by hash(no_w_id) partitions 9;

create table bmsql_oorder (
o_w_id       integer      not null,
o_d_id       integer      not null,
o_id         integer      not null,
o_c_id       integer,
o_carrier_id integer,
o_ol_cnt     integer,
o_all_local  integer,
o_entry_d    timestamp,
PRIMARY KEY (o_w_id, o_d_id, o_id)
)tablegroup='tpcc_group' partition by hash(o_w_id) partitions 9;

create table bmsql_order_line (
ol_w_id         integer   not null,
ol_d_id         integer   not null,
ol_o_id         integer   not null,
ol_number       integer   not null,
ol_i_id         integer   not null,
ol_delivery_d   timestamp,
ol_amount       decimal(6,2),
ol_supply_w_id  integer,
ol_quantity     integer,
ol_dist_info    char(24),
PRIMARY KEY (ol_w_id, ol_d_id, ol_o_id, ol_number)
)tablegroup='tpcc_group' partition by hash(ol_w_id) partitions 9;

create table bmsql_item (
i_id     integer      not null,
i_name   varchar(24),
i_price  decimal(5,2),
i_data   varchar(50),
i_im_id  integer,
PRIMARY KEY (i_id)
) duplicate_scope='cluster';

create table bmsql_stock (
s_w_id       integer       not null,
s_i_id       integer       not null,
s_quantity   integer,
s_ytd        integer,
s_order_cnt  integer,
s_remote_cnt integer,
s_data       varchar(50),
s_dist_01    char(24),
s_dist_02    char(24),
s_dist_03    char(24),
s_dist_04    char(24),
s_dist_05    char(24),
s_dist_06    char(24),
s_dist_07    char(24),
s_dist_08    char(24),
s_dist_09    char(24),
s_dist_10    char(24),
PRIMARY KEY (s_w_id, s_i_id)
)tablegroup='tpcc_group' use_bloom_filter=true partition by hash(s_w_id) partitions 9;

```

运行如下命令建表。

```test
./runSQL.sh props.ob sql.common/tableCreates_parts.sql

```

### 加载数据

加载数据即数据初始化，仓库数越多加载时间越长。1000 仓可能要近 1 个小时，5000 仓可能要半天以上。具体性能取决于机器配置。

```test
./runLoader.sh props.ob

```

加载数据的 INSERT SQL 使用了 batch insert 特性，这点是在 props.ob 里的 JDBC URL 里指定的。开启该特性的写入性能会有明显提升。

### 创建索引

当数据初始化完成后，登录到 tes t租户，在 tpccdb 中补充创建如下两个索引。

```sql
[root@obce-0000 run]# cat sql.common/indexCreates.sql
create index bmsql_customer_idx1
  on  bmsql_customer (c_w_id, c_d_id, c_last, c_first) local;
create  index bmsql_oorder_idx1
  on  bmsql_oorder (o_w_id, o_d_id, o_carrier_id, o_id) local;

```

## 开始测试

在开始性能测试之前，建议您先登录到 sys 租户使用管理员账号做一次集群合并（ major freeze ），获得更好的测试结果。您可以通过如下的方式手动触发合并。当然，这个过程并不是必须的。

```sql
obclient -h127.0.0.1 -P2881 -uroot@sys  -Doceanbase -A -p -c
obclient[oceanbase]> ALTER SYSTEM MAJOR FREEZE;

```

当看到如下查询返回 IDLE 时，表示合并完成

```sql
MySQL [oceanbase]> select name,info from __all_zone where zone='' and name = 'merge_status';
+--------------+------+
| name         | info |
+--------------+------+
| merge_status | IDLE |
+--------------+------+
1 row in set (0.001 sec)

```

合并完成后，开始执行测试：

```test
./runBenchmark.sh props.ob

```

TPC-C 用 tpmC 值（Transactions per Minute）来衡量系统最大有效吞吐量。其中 Transactions 以 NewOrder Transaction 为准，即最终衡量单位为每分钟处理的订单数。

## 体验 OceanBase Scalable OLTP

上面的测试中，不管是单节点集群测试，还是多节点集群，默认情况下参与事务处理的只有一个副本 ZONE，及租户 leader 所在的副本。这是因为默认设置下，租户的 leader 是按照 ZONE 维度以一定优先级分布的。 OceanBase 作为分布式数据库，用户可以选择将一个租户的所有数据分区的多个 leader 打散 shuffle 到多个副本上，实现计算处理能力的多机线性扩展。 如果您的集群环境是三节点或更多节点的配置，您只需以管理员身份执行以下命令，然后再次启动测试，即可体验分布式集群在扩展模式下的处理能力。

```sql
alter tenant test set primary_zone='RANDOM';

```

打散完成后，再次执行测试，可以观察到结果以近似线性的程度提升。

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
