---
title: "OceanBase 数据库 TPC-H 测试 | OceanBase 文档中心"
description: OceanBase 数据库 TPC-H 测试 什么是 TPC-H TPC-H（商业智能计算测试）是美国交易处理效能委员会（TPC，Transaction Processing Performance Council）组织制定的用来模拟决策支持类应用的一个测试集。目前，学术界和工业界普遍采用 TPC-H 来评价决策支持…
---
切换语言

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

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

# OceanBase 数据库 TPC-H 测试

更新时间：2023-08-07 17:30:32

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V3.1.1/zh-CN/300.performance-whitepaper/100.run-the-tpc-h-benchmark-on-oceanbase-database.md)  

## 什么是 TPC-H

TPC-H（商业智能计算测试）是美国交易处理效能委员会（TPC，Transaction Processing Performance Council）组织制定的用来模拟决策支持类应用的一个测试集。目前，学术界和工业界普遍采用 TPC-H 来评价决策支持技术方面应用的性能。这种商业测试可以全方位评测系统的整体商业计算综合能力，对厂商的要求更高，同时也具有普遍的商业实用意义，目前在银行信贷分析和信用卡分析、电信运营分析、税收分析、烟草行业决策分析中都有广泛的应用。

TPC-H 基准测试由 TPC-D（由 TPC 于 1994 年制定的标准，用于决策支持系统方面的测试基准）发展而来的。TPC-H 用 3NF 实现了一个数据仓库，共包含 8 个基本关系，其主要评价指标是各个查询的响应时间，即从提交查询到结果返回所需时间。TPC-H 基准测试的度量单位是每小时执行的查询数（QphH@size），其中 H 表示每小时系统执行复杂查询的平均次数，size 表示数据库规模的大小，它能够反映出系统在处理查询时的能力。TPC-H 是根据真实的生产运行环境来建模的，这使得它可以评估一些其他测试所不能评估的关键性能参数。总而言之，TPC 组织颁布的TPC-H 标准满足了数据仓库领域的测试需求，并且促使各个厂商以及研究机构将该项技术推向极限。

## 环境准备

测试前请按照如下要求准备您的测试环境：

- JDK：建议使用 1.8u131 及以上版本
 - make：yum install make
 - gcc：yum install gcc
 - mysql-devel：yum install mysql-devel
 - Python 连接数据库的驱动：sudo yum install MySQL-python
 - prettytable：pip install prettytable
 - JDBC：建议使用mysql-connector-java-5.1.47版本。
 - tpch tool：点击 [下载地址](https://www.tpc.org/tpc_documents_current_versions/download_programs/tools-download-request5.asp?bm_type=TPC-H&bm_vers=3.0.0&mode=CURRENT-ONLY) 获取
 - OBClient：详细信息，参考 [OBClient 文档](https://github.com/oceanbase/obclient/blob/master/README.md)。
 - OceanBase 数据库：详细信息，参考 [快速入门指南](https://www.oceanbase.com/docs/community-observer-cn-1000000000055977)。
 - 租户规格：

  ```unknow
  create resource unit tpch_unit max_cpu 26, max_memory 60000000000, max_iops 128, max_disk_size 53687091200, max_session_num 64, MIN_CPU=26, MIN_MEMORY=60000000000, MIN_IOPS=128;
  create resource pool tpch_pool unit = 'tpch_unit', unit_num = 1, zone_list=('zone1','zone2','zone3');
  create tenant tpch_mysql resource_pool_list=('tpch_pool'), charset=utf8mb4, replica_num=3, zone_list('zone1', 'zone2', 'zone3'), primary_zone=RANDOM, locality='F@zone1,F@zone2,F@zone3' set variables ob_compatibility_mode='mysql', ob_tcp_invited_nodes='%';

  ```

  **注意**

     - 上文的租户规格是基于 [OceanBase TPC-H 性能测试报告](https://www.oceanbase.com/docs/community-observer-cn-10000000000013219) 中的硬件配置进行配置的，您需根据自身数据库的硬件配置进行动态调整。详细操作，参考 [修改租户](https://www.oceanbase.com/docs/community-observer-cn-10000000000014146)。
     - 进行性能测试时，租户需配置最大可用资源。

## 部署集群

1. 使用 OBD 部署 OceanBase 数据库集群。

   OceanBase 集群规模为 1：1：1。
 2. 部署成功后，新建执行 TPC-H 测试的租户及用户（请勿直接使用 sys 租户进行测试）。将租户的 `primary_zone` 设置为 `RANDOM`。租户详情，参考 [创建用户租户。](https://www.oceanbase.com/docs/community-observer-cn-10000000000014143)

   `RANDOM` 表示新建表分区的 Leader 随机到这 3 台机器。

## 进行环境调优

请在系统租户下进行环境调优。

1. OceanBase 数据库调优。

   在系统租户下执行 `obclient -h$host_ip -P$host_port -uroot@sys -A` 命令。

   ```unknow
   #调整 sys 租户占用的内存，以提供测试租户更多资源，需根据实际环境动态调整
   alter system set system_memory='15g';
   alter resource unit sys_unit_config max_memory='15g',min_memory='15g';
   #调优参数
   alter system set enable_merge_by_turn= False;
   alter system set trace_log_slow_query_watermark='100s';
   alter system set max_kept_major_version_number=1;
   alter system set enable_sql_operator_dump=True;
   alter system set _hash_area_size='3g';
   alter system set memstore_limit_percentage=50;
   alter system set enable_rebalance=False;
   alter system set memory_chunk_cache_size='0';
   alter system set minor_freeze_times=5;
   alter system set merge_thread_count=20;
   alter system set cache_wash_threshold='30g';
   ##调整日志级别及保存个数
   alter system set syslog_level='PERF';
   alter system set max_syslog_file_count=100;
   alter system set enable_syslog_recycle='True';

   ```
 2. 设置租户。

   在测试用户下执行 `obclient -h$host_ip -P$host_port -u$user@$tenant -p$password -A` 命令。

   ```unknow
   #设置全局参数
   set global ob_sql_work_area_percentage=80;
   set global optimizer_use_sql_plan_baselines = true;
   set global optimizer_capture_sql_plan_baselines = true;
   alter system set ob_enable_batched_multi_statement='true';
   ##租户下设置，防止事务超时
   set global ob_query_timeout=36000000000;
   set global ob_trx_timeout=36000000000;
   set global max_allowed_packet=67108864;
   set global secure_file_priv="";
   /*
   parallel_max_servers 推荐设置为测试租户分配的 resource unit cpu 数的 10 倍
   如测试租户使用的 unit 配置为：create resource unit $unit_name max_cpu 26
   那么该值设置为 260
   parallel_server_target 推荐设置为 parallel_max_servers * 机器数*0.8
   那么该值为 260*3*0.8=624
   */
   set global parallel_max_servers=260;
   set global parallel_servers_target=624;

   ```
 3. 调优参数设置完毕请重启集群：obd cluster restart $cluster_name --wop

   wop 即无参启动。启动的时候不带参数。节点第一次的启动时，不响应此选项。

## 进行 TPC-H 测试

### 安装 TPC-H Tool

下载 TPC-H Tool。详细信息参考 [TPC-H Tool 下载页面](https://www.tpc.org/tpc_documents_current_versions/download_programs/tools-download-request5.asp?bm_type=TPC-H&bm_vers=3.0.0&mode=CURRENT-ONLY)。

下载完成后解压文件，进入 TPC-H 解压后的目录。

```unknow
[wieck@localhost ~] $ unzip 7e965ead-8844-4efa-a275-34e35f8ab89b-tpc-h-tool.zip
[wieck@localhost ~] $ cd TPC-H_Tools_v3.0.0

```

复制 `Makefile.suite`。

```unknow
[wieck@localhost TPC-H_Tools_v3.0.0] $ cd dbgen/
[wieck@localhost dbgen] $ cp Makefile.suite Makefile

```

修改 `Makefile` 文件中的 CC、DATABASE、MACHINE、WORKLOAD 等参数定义。

```unknow
CC      = gcc
# Current values for DATABASE are: INFORMIX, DB2, TDAT (Teradata)
#                                  SQLSERVER, SYBASE, ORACLE, VECTORWISE
# Current values for MACHINE are:  ATT, DOS, HP, IBM, ICL, MVS,
#                                  SGI, SUN, U2200, VMS, LINUX, WIN32
# Current values for WORKLOAD are:  TPCH
DATABASE= MYSQL
MACHINE = LINUX
WORKLOAD = TPCH

```

修改 `tpcd.h` 文件，并添加新的宏定义。

```unknow
#ifdef MYSQL
#define GEN_QUERY_PLAN ""
#define START_TRAN "START TRANSACTION"
#define END_TRAN "COMMIT"
#define SET_OUTPUT ""
#define SET_ROWCOUNT "limit %d;\n"
#define SET_DBASE "use %s;\n"
#endif

```

编译文件。

```unknow
make

```

### 生成数据

您可以根据实际环境生成 TCP-H 10G、100G 或者 1T 数据。本文以生成 100G 数据为例。

```unknow
./dbgen -s 100
mkdir tpch100
mv *.tbl tpch100

```

### 生成查询 SQL

复制 `qgen` 和 `dists.dss` 文件至 `queries` 目录。

```unknow
cp qgen queries
cp dists.dss queries

```

在 `queries` 目录下创建 `gen.sh` 脚本生成查询 SQL。

```unknow
#!/usr/bin/bash
for i in {1..22}
do  
  ./qgen -d $i -s 100 > db"$i".sql
done

```

执行 `gen.sh` 脚本。

```unknow
chmod +x  gen.sh
./gen.sh

```

查询 SQL 进行调整。

```unknow
dos2unix *

```

去掉生成文件中的 `limit -xx（OB不支持limit 负数的语法）` , 去掉 day 后的 (3), 加上`parallel(96)` 并发，以 q1 为例， SQL 如下：

```unknow
SELECT  /*+    parallel(96) */   ---增加 parallel 并发执行
    l_returnflag,
    l_linestatus,
    sum(l_quantity) as sum_qty,
    sum(l_extendedprice) as sum_base_price,
    sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
    sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
    avg(l_quantity) as avg_qty,
    avg(l_extendedprice) as avg_price,
    avg(l_discount) as avg_disc,
    count(*) as count_order
from
    lineitem
where
    l_shipdate <= date'1998-12-01' - interval '90' day (3) ---去掉（3）
group by
    l_returnflag,
    l_linestatus
order by
    l_returnflag,
    l_linestatus;
limit -1;              ---  去掉这行

```

### 新建表

创建表结构文件 `create_tpch_mysql_table_part.ddl`。

```sql
create tablegroup if not exists tpch_tg_100g_lineitem_order_group binding true partition by key 1 partitions 192;
create tablegroup if not exists tpch_tg_100g_partsupp_part binding true partition by key 1 partitions 192;

drop database if exists $db_name;
create database $db_name;
use $db_name;

    create table lineitem (
    l_orderkey bigint not null,
    l_partkey bigint not null,
    l_suppkey bigint not null,
    l_linenumber bigint not null,
    l_quantity bigint not null,
    l_extendedprice bigint not null,
    l_discount bigint not null,
    l_tax bigint not null,
    l_returnflag char(1) default null,
    l_linestatus char(1) default null,
    l_shipdate date not null,
    l_commitdate date default null,
    l_receiptdate date default null,
    l_shipinstruct char(25) default null,
    l_shipmode char(10) default null,
    l_comment varchar(44) default null,
    primary key(l_orderkey, l_linenumber))
    tablegroup = tpch_tg_100g_lineitem_order_group
    partition by key (l_orderkey) partitions 192;
    create index I_L_ORDERKEY on lineitem(l_orderkey) local;
    create index I_L_SHIPDATE on lineitem(l_shipdate) local;

    create table orders (
    o_orderkey bigint not null,
    o_custkey bigint not null,
    o_orderstatus char(1) default null,
    o_totalprice bigint default null,
    o_orderdate date not null,
    o_orderpriority char(15) default null,
    o_clerk char(15) default null,
    o_shippriority bigint default null,
    o_comment varchar(79) default null,
    primary key (o_orderkey))
    tablegroup = tpch_tg_100g_lineitem_order_group
    partition by key(o_orderkey) partitions 192;
    create index I_O_ORDERDATE on orders(o_orderdate) local;

    create table partsupp (
    ps_partkey bigint not null,
    ps_suppkey bigint not null,
    ps_availqty bigint default null,
    ps_supplycost bigint default null,
    ps_comment varchar(199) default null,
    primary key (ps_partkey, ps_suppkey))
    tablegroup tpch_tg_100g_partsupp_part
    partition by key(ps_partkey) partitions 192;

    create table part (
  p_partkey bigint not null,
  p_name varchar(55) default null,
  p_mfgr char(25) default null,
  p_brand char(10) default null,
  p_type varchar(25) default null,
  p_size bigint default null,
  p_container char(10) default null,
  p_retailprice bigint default null,
  p_comment varchar(23) default null,
  primary key (p_partkey))
  tablegroup tpch_tg_100g_partsupp_part
  partition by key(p_partkey) partitions 192;

    create table customer (
  c_custkey bigint not null,
  c_name varchar(25) default null,
  c_address varchar(40) default null,
  c_nationkey bigint default null,
  c_phone char(15) default null,
  c_acctbal bigint default null,
  c_mktsegment char(10) default null,
  c_comment varchar(117) default null,
  primary key (c_custkey))
  partition by key(c_custkey) partitions 192;

  create table supplier (
  s_suppkey bigint not null,
  s_name char(25) default null,
  s_address varchar(40) default null,
  s_nationkey bigint default null,
  s_phone char(15) default null,
  s_acctbal bigint default null,
  s_comment varchar(101) default null,
  primary key (s_suppkey)
) partition by key(s_suppkey) partitions 192;

    create table nation (
  n_nationkey bigint not null,
  n_name char(25) default null,
  n_regionkey bigint default null,
  n_comment varchar(152) default null,
  primary key (n_nationkey));

    create table region (
  r_regionkey bigint not null,
  r_name char(25) default null,
  r_comment varchar(152) default null,
  primary key (r_regionkey));

```

### 加载数据

您可以根据上述步骤生成的数据和 SQL 自行编写脚本。加载数据示例操作如下：

1. 创建加载脚本目录。

   ```unknow
   mkdir load
   cd load
   cp ../dss.ri  ../dss.ddl ./

   ```
 2. 创建 `load.py` 脚本。

   ```unknow
   $cat load.py
   #/usr/bin/evn python
   #-*- encoding:utf-8 -*-
   import os
   import sys
   import time
   import commands
   hostname='$host_ip'  #注意！！请填写某个 observer，如 observer A 所在服务器的 IP 地址
   port='$host_port'               #observer A 的端口号
   tenant='$tenant_name'              #租户名
   user='$user'               #用户名
   password='$password'           #密码
   data_path='$path'         #注意！！请填写 observer A 所在服务器下 tbl 所在目录
   db_name='$db_name'             #数据库名
   #创建表
   cmd_str='obclient -h%s -P%s -u%s@%s -p%s < create_tpch_mysql_table_part.ddl'%(hostname,port,user,tenant,password)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str='obclient -h%s -P%s -u%s@%s -p%s  -D%s -e "show tables;" '%(hostname,port,user,tenant,password,db_name)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/customer.tbl' into table customer fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/lineitem.tbl' into table lineitem fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/nation.tbl' into table nation fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/orders.tbl' into table orders fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s   -D%s -e "load data /*+ parallel(80) */ infile '%s/partsupp.tbl' into table partsupp fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/part.tbl' into table part fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/region.tbl' into table region fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result
   cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c  -D%s -e "load data /*+ parallel(80) */ infile '%s/supplier.tbl' into table supplier fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path)
   result = commands.getstatusoutput(cmd_str)
   print result

   ```
 3. 加载数据。

   **注意**

   加载数据需要安装 obclient 客户端。

   ```unknow
   $python load.py
   (0,'')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.\nTABLE_NAME\nT1\nLINEITEM\nORDERS\nPARTSUPP\nPART\nCUSTOMER\nSUPPLIER\nNATION\nREGION')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
   (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')

   ```
 4. 执行合并。

   Major 合并将当前大版本的 SSTable 和 MemTable 与前一个大版本的全量静态数据进行合并，使存储层统计信息更准确，生成的执行计划更稳定。 **注意**

   执行合并需要使用 sys 租户登录。

   ```unknow
   MySQL [(none)]> use oceanbase
   Database changed
   MySQL [oceanbase]> alter system major freeze;
   Query OK, 0 rows affected

   ```
 5. 查看合并是否完成。

   ```unknow
   MySQL [oceanbase]> select name,value from oceanbase.__all_zone where name='frozen_version' or name='last_merged_version';
   +---------------------+-------+
   | name                | value |
   +---------------------+-------+
   | frozen_version      |     2 |
   | last_merged_version |     2 |
   | last_merged_version |     2 |
   | last_merged_version |     2 |
   | last_merged_version |     2 |
   +---------------------+-------+

   ```

   `frozen_version` 和所有 zone 的 `last_merged_version` 的值相等即表示合并完成。

### 执行测试

您可以根据上述步骤生成的数据和 SQL 自行编写脚本。执行测试示例操作如下：

1. 在 `queries` 目录下编写测试脚本 `tpch.sh`。

   ```unknow
   #!/bin/bash
   TPCH_TEST="obclient -h $host_ip -P $host_port -utpch_100g_part@tpch_mysql  -D tpch_100g_part  -ptest -c"
   #warmup预热
   for i in {1..22}
   do
       sql1="source db${i}.sql"
       echo $sql1| $TPCH_TEST >db${i}.log  || ret=1
   done
   #正式执行
   for i in {1..22}
   do
       starttime=`date +%s%N`
       echo `date  '+[%Y-%m-%d %H:%M:%S]'` "BEGIN Q${i}"
       sql1="source db${i}.sql"
       echo $sql1| $TPCH_TEST >db${i}.log  || ret=1
       stoptime=`date +%s%N`
       costtime=`echo $stoptime $starttime | awk '{printf "%0.2f\n", ($1 - $2) / 1000000000}'`
       echo `date  '+[%Y-%m-%d %H:%M:%S]'` "END,COST ${costtime}s"
   done

   ```
 2. 执行测试脚本。

   ```unknow
   sh tpch.sh

   ```

**说明**

测试结果可参考 [OceanBase TPC-H 性能测试报告](https://www.oceanbase.com/docs/community-observer-cn-10000000000013219)。

## FAQ

- 导入数据失败。报错信息如下：

  ```unknow
  ERROR 1017 (HY000) at line 1: File not exist

  ```

  tbl 文件必须放在所连接的 OceanBase 数据库所在机器的某个目录下，因为加载数据必须本地导入。
 - 查看数据报错。报错信息如下：

  ```unknow
  ERROR 4624 (HY000)：No memory or reach tenant memory limit

  ```

  内存不足，建议增大租户内存。
 - 导入数据报错。报错信息如下：

  ```unknow
  ERROR 1227 (42501) at line 1: Access denied

  ```

  需要授予用户访问权限。运行以下命令，授予权限：

  ```unknow
  grant file on *.* to tpch_100g_part;

  ```

 上一篇 下一篇 ![有帮助](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) 咨询热线
