1. 程式人生 > 資料庫 >資料庫壓測模型TPC-C/TPC-H

資料庫壓測模型TPC-C/TPC-H

在資料庫選型、新系統上線時,常常需要對資料庫效能進行測試。資料庫效能測試的工具有很多,比如常見的sysbench,但sysbench只能進行單表的壓測,不能模擬接近生產系統的複雜的業務模型。
TPC , Transaction Processing Performance Council,是一個非盈利組織,成立於1988年,這個組織主要的功能是定義事務處理、資料庫的基準,這個基準用於評估伺服器的效能,並且把伺服器評估的結果釋出在TPC的官方網站上。簡單的講TPC就是系統評測皇家科學院。
絕大部分資料庫產品在釋出時都會進行TPC壓力測試,阿里OceanBase在2019年10月的TPC-C測試中,跑出6000萬+的測試成績,成為TPC-C榜單第一名。

image

針對不同的業務場景,TPC有對應的不同的測試模型,比較常用的有針對OLTP的TPC-C及針對OLAP的TPC-H,本文詳細介紹TPC-C及TPC-H測試模型及測試過程。

一、TPC-C
TPC-C is an On-Line Transaction Processing Benchmark.
TPC-C is measured in transactions per minute (tpmC).

TPC-C是業界常用的一套benchmark,由TPC委員會制定釋出,用於評測資料庫的聯機交易處理(OLTP)能力。主要涉及10張表,包含五類業務事務模型(NewOrder–新訂單的生成、Payment–訂單付款、OrderStatus–最近訂單查詢、Delivery–配送、StockLevel–庫存缺貨狀態分析)。

TPC-C事務模型
TPC-C需要處理的交易事務主要為以下幾種:
1、新訂單(New-Order) :客戶輸入一筆新的訂貨交易;
2、支付操作(Payment) :更新客戶帳戶餘額以反映其支付狀況;
3、發貨(Delivery) :發貨(模擬批處理交易);
4、訂單狀態查詢(Order-Status) :查詢客戶最近交易的狀態;
5、庫存狀態查詢(Stock-Level) :查詢倉庫庫存狀況,以便能夠及時補貨。

TPC-C通過tpmC值(Transactions per Minute)來衡量系統最大有效吞吐量(MQTh,Max Qualified Throughput),其中Transactions以NewOrder Transaction為準,即最終衡量單位為每分鐘處理的新訂單數

TPC-C效能衡量指標tpmC
流量指標(Throughput,簡稱tpmC):按照TPC組織的定義,流量指標描述了系統在執行支付操作、訂單狀態查詢、發貨和庫存狀態查詢這4種交易的同時,每分鐘可以處理多少個新訂單交易。所有交易的響應時間必須滿足TPC-C測試規範的要求,且各種交易數量所佔的比例也應該滿足TPC-C測試規範的要求。在這種情況下,流量指標值越大說明系統的聯機事務處理能力越高。

TPC-C表模型
image

依據TPC-C模型,有很多不同的測試工具,如Percorna公司的TPCC-MYSQL, BenchmarkSQL等。因為BenchmarkSQL支援多種TPC模型,並且支援不同的資料庫型別(如Oracle, PG, MySQL), 本篇文章介紹BenchmarkSQL.

BenchmarkSQL TPC-C測試mysql演示:
1.登入MySQL資料庫伺服器,建立資料庫tpcc。
mysql> create database tpcc;
show databases;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| tpcc |
+--------------------+
5 rows in set (0.00 sec)

mysql> use tpcc;
Database changed
mysql> show tables;
Empty set (0.00 sec)

mysql>

2.BenchmarkSQL可以在官網下載5.0(測試mysql需要做修改),或者下載pingcap修改過的測試mysql的版本 

unzip BenchMarkSQL.zip
cd /home/BenchMarkSQL/run
vi props.mysql

[root@mysql5702 run]# cat props.mysql
db=mysql
driver=com.mysql.cj.jdbc.Driver
conn=jdbc:mysql://192.168.56.58:3306/tpcc
user=root
password=oracle

warehouses=5
loadWorkers=20

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

//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
[root@mysql5702 run]#

warehouses=5 --warehouses數量,決定load多大的資料量,1個warehouse對應30000customer,300000資料量
terminals=10 --併發數
runMins=10 --測試多場時間(分鐘)

  1. 登入Benchmarksql客戶端,向MySQL資料庫伺服器匯入資料(建立表並初始化)。
    #./runDatabaseBuild.sh props.mysql

該指令碼將呼叫對應的sql檔案,建立表、索引並load資料,有興趣可以檢視run目錄下的各個sh檔案內容

完成後,可以看到9張業務表1張配置表已經建立:
mysql> show tables;
+------------------+
| Tables_in_tpcc |
+------------------+
| bmsql_config |
| bmsql_customer |
| bmsql_district |
| bmsql_history |
| bmsql_item |
| bmsql_new_order |
| bmsql_oorder |
| bmsql_order_line |
| bmsql_stock |
| bmsql_warehouse |
+------------------+
10 rows in set (0.01 sec)

mysql>

4.登入Benchmarksql客戶端,執行Benchmarksql程式對MySQL資料庫伺服器進行壓力測試。
./runBenchmark.sh props.mysql

按照配置的runMins=10 執行10分鐘的TPC-C壓測,並得出最終的tpmC值。
tpmC (NewOrders) = 30872.68

[ run]# ./runBenchmark.sh props.mysql
18:50:31,673 [main] INFO jTPCC : Term-00,
18:50:31,675 [main] INFO jTPCC : Term-00, +-------------------------------------------------------------+
18:50:31,675 [main] INFO jTPCC : Term-00, BenchmarkSQL v5.0
18:50:31,675 [main] INFO jTPCC : Term-00, +-------------------------------------------------------------+
18:50:31,675 [main] INFO jTPCC : Term-00, (c) 2003, Raul Barbosa
18:50:31,675 [main] INFO jTPCC : Term-00, (c) 2004-2016, Denis Lussier
18:50:31,677 [main] INFO jTPCC : Term-00, (c) 2016, Jan Wieck
18:50:31,677 [main] INFO jTPCC : Term-00, +-------------------------------------------------------------+
18:50:31,677 [main] INFO jTPCC : Term-00,
18:50:31,677 [main] INFO jTPCC : Term-00, db=mysql
18:50:31,677 [main] INFO jTPCC : Term-00, driver=com.mysql.cj.jdbc.Driver
18:50:31,677 [main] INFO jTPCC : Term-00, conn=jdbc:mysql://10.90.155.30:33066/tpcc
18:50:31,677 [main] INFO jTPCC : Term-00, user=root
18:50:31,678 [main] INFO jTPCC : Term-00,
18:50:31,678 [main] INFO jTPCC : Term-00, warehouses=10
18:50:31,678 [main] INFO jTPCC : Term-00, terminals=5
18:50:31,679 [main] INFO jTPCC : Term-00, runMins=10
18:50:31,679 [main] INFO jTPCC : Term-00, limitTxnsPerMin=1000000000
18:50:31,679 [main] INFO jTPCC : Term-00, terminalWarehouseFixed=true
18:50:31,679 [main] INFO jTPCC : Term-00,
18:50:31,679 [main] INFO jTPCC : Term-00, newOrderWeight=45
18:50:31,679 [main] INFO jTPCC : Term-00, paymentWeight=43
18:50:31,679 [main] INFO jTPCC : Term-00, orderStatusWeight=4
18:50:31,680 [main] INFO jTPCC : Term-00, deliveryWeight=4
18:50:31,680 [main] INFO jTPCC : Term-00, stockLevelWeight=4
18:50:31,680 [main] INFO jTPCC : Term-00,
18:50:31,680 [main] INFO jTPCC : Term-00, resultDirectory=null
18:50:31,680 [main] INFO jTPCC : Term-00, osCollectorScript=null
18:50:31,680 [main] INFO jTPCC : Term-00,
18:50:31,893 [main] INFO jTPCC : Term-00, C value for C_LAST during load: 229
18:50:31,894 [main] INFO jTPCC : Term-00, C value for C_LAST this run: 114
18:50:31,894 [main] INFO jTPCC : Term-00,
Term-00, Running Average tpmTOTAL: 68679.74 Current tpmTOTAL: 4542300 Memory Usage: 157MB / 1442MB
19:00:31,958 [Thread-1] INFO jTPCC : Term-00,
19:00:31,958 [Thread-1] INFO jTPCC : Term-00,
19:00:31,959 [Thread-1] INFO jTPCC : Term-00, Measured tpmC (NewOrders) = 30872.68
19:00:31,959 [Thread-1] INFO jTPCC : Term-00, Measured tpmTOTAL = 68679.22
19:00:31,959 [Thread-1] INFO jTPCC : Term-00, Session Start = 2020-12-28 18:50:31
19:00:31,959 [Thread-1] INFO jTPCC : Term-00, Session End = 2020-12-28 19:00:31
19:00:31,959 [Thread-1] INFO jTPCC : Term-00, Transaction Count = 686805
[ run]#

5.清理測試資料表
./runDatabaseDestroy.sh props.mysql

32C180G記憶體,10 warehouse 下MySQL和PG TPC-C測試結果:
image

二、TPC-H
TPC-H 是業界常用的一套 Benchmark,由 TPC 委員會制定釋出,用於評測資料庫的分析型查詢能力。TPC-H 查詢包含 8 張資料表、22 條複雜的 SQL 查詢,大多數查詢包含若干表 Join、子查詢和 Group-by 聚合等。

簡單來說,TPC-H就是通過22個複雜SQL查詢來評估資料庫OLAP的效能。

22條SQL業務邏輯分析可參考TPC-H官方文件或 

The TPC Benchmark™H (TPC-H) is a decision support benchmark. It consists of a suite of business oriented ad-hoc queries and concurrent data modifications. The queries and the data populating the database have been chosen to have broad industry-wide relevance while maintaining a sufficient degree of ease of implementation. This benchmark illustrates decision support systems that
• Examine large volumes of data;
• Execute queries with a high degree of complexity;
• Give answers to critical business questions.

TPC-H 表模型:
image

TPC-H測試mysql演示:

  1. 官方TPC-H工具包可在官網 
  2. unzip TPC-H_Tools_v2.18.0.zip, 解壓後進入/usr/local/2.18.0_rc2/dbgen 修改 makefile.suite檔案,修改103~112行。
    ################
    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

改好之後,儲存成makefile檔案
cp makefile.suite makefile
3. 修改tpcd.h檔案。
開啟tpcd.h,在檔案末尾加入下面的巨集定義。

#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

  1. 編譯
    在dbgen目錄下編譯: make
    編譯之後會生成很多的.o目標檔案
  2. 生成.tbl資料檔案。
    接下來要用dbgen生成資料,一共會生成8個表(.tbl)。生成1G資料。其中1表示生成1G資料。如果你想生成10G,將1改為10。可以通過./dbgen -h檢視dbgen的引數選項。

./dbgen -s 1
[root@mysql5702 dbgen]# ./dbgen -s 1
TPC-H Population Generator (Version 2.18.0)
Copyright Transaction Processing Performance Council 1994 - 2010
[root@mysql5702 dbgen]# ls *tbl
customer.tbl lineitem.tbl nation.tbl orders.tbl partsupp.tbl part.tbl region.tbl supplier.tbl
[root@mysql5702 dbgen]#

6.修改初始化指令碼使MySQL可用。
dss.ddl:建表指令碼
dss.ri:建立primary key和foreign key指令碼

不過這些指令碼不能直接在MySQL裡用,需要修改。

6.1 修改dss.ddl
dss.ddl的開頭需要加上一些給MySQL建立資料庫連線用的指令。在最前面加上如下程式碼:
DROP DATABASE tpch;
CREATE DATABASE tpch;
USE tpch;
並且將表名全部改為小寫字母。

[root@mysql5701 dbgen]# cat dss.ddl
-- Sccsid: @(#)dss.ddl 2.1.8.1
DROP DATABASE tpch;
CREATE DATABASE tpch;
USE tpch;
create table nation ( n_nationkey integer not null,
n_name char(25) not null,
n_regionkey integer not null,
n_comment varchar(152));

create table region ( r_regionkey integer not null,
r_name char(25) not null,
r_comment varchar(152));

create table part ( p_partkey integer not null,
p_name varchar(55) not null,
p_mfgr char(25) not null,
p_brand char(10) not null,
p_type varchar(25) not null,
p_size integer not null,
p_container char(10) not null,
p_retailprice decimal(15,2) not null,
p_comment varchar(23) not null );

create table supplier ( s_suppkey integer not null,
s_name char(25) not null,
s_address varchar(40) not null,
s_nationkey integer not null,
s_phone char(15) not null,
s_acctbal decimal(15,2) not null,
s_comment varchar(101) not null);

create table partsupp ( ps_partkey integer not null,
ps_suppkey integer not null,
ps_availqty integer not null,
ps_supplycost decimal(15,2) not null,
ps_comment varchar(199) not null );

create table customer ( c_custkey integer not null,
c_name varchar(25) not null,
c_address varchar(40) not null,
c_nationkey integer not null,
c_phone char(15) not null,
c_acctbal decimal(15,2) not null,
c_mktsegment char(10) not null,
c_comment varchar(117) not null);

create table orders ( o_orderkey integer not null,
o_custkey integer not null,
o_orderstatus char(1) not null,
o_totalprice decimal(15,2) not null,
o_orderdate date not null,
o_orderpriority char(15) not null,
o_clerk char(15) not null,
o_shippriority integer not null,
o_comment varchar(79) not null);

create table lineitem ( l_orderkey integer not null,
l_partkey integer not null,
l_suppkey integer not null,
l_linenumber integer not null,
l_quantity decimal(15,2) not null,
l_extendedprice decimal(15,2) not null,
l_discount decimal(15,2) not null,
l_tax decimal(15,2) not null,
l_returnflag char(1) not null,
l_linestatus char(1) not null,
l_shipdate date not null,
l_commitdate date not null,
l_receiptdate date not null,
l_shipinstruct char(25) not null,
l_shipmode char(10) not null,
l_comment varchar(44) not null);
[root@mysql5701 dbgen]#

6.2 修改dss.ri
USE tpch;
alter table tpch.region add primary key (r_regionkey);

alter table tpch.nation add primary key (n_nationkey);

create index idx1_nation on tpch.nation(n_regionkey);

commit work;

alter table tpch.part add primary key (p_partkey);

commit work;

alter table tpch.supplier add primary key (s_suppkey);

create index idx1_supplier on tpch.supplier(s_nationkey);

commit work;

alter table tpch.partsupp add primary key (ps_partkey,ps_suppkey);

commit work;

alter table tpch.customer add primary key (c_custkey);

create index idx1_customer on tpch.customer(c_nationkey);

commit work;

alter table tpch.lineitem add primary key (l_orderkey,l_linenumber);

commit work;

alter table tpch.orders add primary key (o_orderkey);

commit work;

create index idx1_partsupp on tpch.partsupp(ps_suppkey);

commit work;

create index idx2_partsupp on tpch.partsupp(ps_partkey);

commit work;

create index idx1_orders on tpch.orders(o_custkey);

commit work;

create index idx1_lineitem on tpch.lineitem(l_orderkey);

commit work;

create index idx2_lineitem on tpch.lineitem(l_partkey,l_suppkey);

commit work;

7.建tpch資料庫及表。
呼叫dss.ddl建立庫及表
mysql> source /usr/local/2.18.0_rc2/dbgen/dss.ddl
呼叫dss.ri建立主鍵及索引
mysql> source /usr/local/2.18.0_rc2/dbgen/dss.ri

8.匯入資料。
建立以下load.sh檔案並執行,生成loaddata.sql:
[root@mysql5702 dbgen]# cat load.sh
#!/bin/bash

write_to_file()
{
file="loaddata.sql"

if [ ! -f "$file" ] ; then
touch "$file"
fi

echo 'USE tpch;' >> $file
echo 'SET FOREIGN_KEY_CHECKS=0;' >> $file

DIR=pwd
for tbl in ls *.tbl; do
table=$(echo "${tbl%.*}")
echo "LOAD DATA LOCAL INFILE '$DIR/$tbl' INTO TABLE $table" >> $file
echo "FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';" >> $file
done
echo 'SET FOREIGN_KEY_CHECKS=1;' >> $file
}

write_to_file
[root@mysql5702 dbgen]#

[root@mysql5702 dbgen]# cat loaddata.sql
USE tpch;
SET FOREIGN_KEY_CHECKS=0;
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/customer.tbl' INTO TABLE customer
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/lineitem.tbl' INTO TABLE lineitem
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/nation.tbl' INTO TABLE nation
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/orders.tbl' INTO TABLE orders
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/partsupp.tbl' INTO TABLE partsupp
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/part.tbl' INTO TABLE part
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/region.tbl' INTO TABLE region
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
LOAD DATA LOCAL INFILE '/usr/local/2.18.0_rc2/dbgen/supplier.tbl' INTO TABLE supplier
FIELDS TERMINATED BY '|' LINES TERMINATED BY '|\n';
SET FOREIGN_KEY_CHECKS=1;
[root@mysql5702 dbgen]#

執行loaddata.sql匯入資料:
mysql> source /usr/local/2.18.0_rc2/dbgen/loaddata.sql

9.生成查詢sql語句

將qgen執行檔案和dists.dss檔案拷貝到queries模板目錄中。
cp qgen dists.dss queries/
mkdir tpch_sql

export DSS_QUERY=queries
for((i=1;i<=22;i++));
do
queries/qgen -d $i > tpch_sql/$i.sql
done

生成的sql檔案還是有問題,需要做下處理:
image

10.執行sql 1-22,記錄執行時間。ke可以參考以下polarDB整理表格和圖表。

image