§ TPC-H性能测试
本文主要介绍采用 TPC-H 工具对 GreatSQL 进行性能测试的方法。
§ 关于TPC-H
TPC-H是TPC(Transaction Processing Performance Council)组织提供的工具包。主要用于进行OLAP业务场景测试,以评估商业分析中决策支持系统(DSS)的性能。它包含了一整套面向商业的ad-hoc查询和并发数据修改,强调测试的是数据库、平台和I/O性能,关注查询能力。
官网:http://www.tpc.org/tpch (opens new window)
§ 编译安装TPC-H
1. 下载TPC-H
访问TPC-H下载页面 (opens new window),下载源码包。
2. 下载完后,解压缩,并复制 makefile.suite
文件
$ unzip 41aa248b-48a5-11ee-8bef-d08e7908bcb1-tpc-h-tool.zip
$ cd TPC-H_Tools_v3.0.1
$ cd dbgen
$ cp makefile.suite Makefile
2
3
4
3. 修改Makefile以适配
$ vim Makefile
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
2
3
4
5
6
7
8
9
10
4. 修改tpcd.h文件,在文件末尾新增几行MYSQL宏定义
$ vim 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
2
3
4
5
6
7
8
9
5. 编译
执行make编译,编译完毕后会生成两个可执行文件:
- dbgen:数据生成工具。在使用InfiniDB官方测试脚本进行测试时,需要用该工具生成tpch相关表数据。
- qgen:SQL生成工具
§ 生成测试数据
可根据实际情况,生成 1、10、100、1000 等不同数据集比例因子(Scale Factor)级别的测试数据,例如 30:
$ ./dbgen -vf -s 30
最后会生成数个 .tbl 文件:
$ ls -lh
-rw-r--r-- 1 root root 703M Jul 19 15:36 customer.tbl
-rw-r--r-- 1 root root 23G Jul 19 15:36 lineitem.tbl
-rw-r--r-- 1 root root 2.2K Jul 19 15:36 nation.tbl
-rw-r--r-- 1 root root 5.0G Jul 19 15:36 orders.tbl
-rw-r--r-- 1 root root 3.4G Jul 19 15:36 partsupp.tbl
-rw-r--r-- 1 root root 699M Jul 19 15:36 part.tbl
-rw-r--r-- 1 root root 389 Jul 19 15:36 region.tbl
-rw-r--r-- 1 root root 41M Jul 19 15:36 supplier.tbl
2
3
4
5
6
7
8
9
还可以利用 pdbgen.sh脚本 (opens new window) 来生成测试数据集,它采用并行的方法,每个大表生成多个文件切片,其效率相比直接调用 dbgen
至少可以提升一倍。这种多文件切片的方式,也更有利于后续采用 pload.sh脚本 (opens new window)) 实现更高效并发导入。
§ 生成TPC-H测试查询SQL
可直接访问gitee仓库获取相应的SQL (opens new window),这些 SQL 脚本文件可直接用于测试 GreatSQL 的 Rapid 引擎,已经加上了相应的 HINT,例如:
-- tpch_queries_1.sql
SELECT /*+ SET_VAR(use_secondary_engine=1) SET_VAR(secondary_engine_cost_threshold=0) */ /*+ Q1 */
l_returnflag,
l_linestatus,
...
2
3
4
5
也可参考下面的方法手动生成22个TPC-H测试查询SQL:
# 生成22个SQL文件
$ for i in $(seq 1 22); do ./qgen -d $i -s 1000 > tpch_queries_"$i".sql; done
# 转换文件格式
$ dos2unix *.sql
2
3
4
5
参数 -s 1000
表示测试数据集比例因子是 1000,不同比例因子的区别在于第 11 个查询SQL中的条件因子,在 tpch_queries_11.sql 中也已注明:
-- cat tpch_queries_11.sql
...
SELECT
sum(ps_supplycost * ps_availqty) * 0.0001000000 /* SF1 */
/* sum(ps_supplycost * ps_availqty) * 0.0000100000 /* SF10 */
/* sum(ps_supplycost * ps_availqty) * 0.0000010000 /* SF100 */
/* sum(ps_supplycost * ps_availqty) * 0.0000001000 /* SF1000 */
FROM
...
2
3
4
5
6
7
8
9
§ 新建TPC-H测试数据库,导入测试数据
§ 初始化TPC-H测试库表
- 下载 tpch-create-table.sql文件 (opens new window),导入数据库,完成TPC-H测试库表初始化。
文件内容如下:
-- DROP DATABASE IF EXISTS tpch;
-- CREATE DATABASE IF NOT EXISTS tpch DEFAULT CHARACTER SET latin1;
-- USE tpch;
drop table if exists nation;
create table nation ( n_nationkey bigint not null,
n_name char(25) not null,
n_regionkey bigint not null,
n_comment varchar(152),
primary key(n_nationkey),
key nation_fk1 (n_regionkey) ) secondary_engine = rapid;
drop table if exists region;
create table region ( r_regionkey bigint not null,
r_name char(25) not null,
r_comment varchar(152),
primary key(r_regionkey) ) secondary_engine = rapid;
drop table if exists part;
create table part ( p_partkey bigint 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,
primary key(p_partkey) ) secondary_engine = rapid;
drop table if exists supplier;
create table supplier ( s_suppkey bigint not null,
s_name char(25) not null,
s_address varchar(40) not null,
s_nationkey bigint not null,
s_phone char(15) not null,
s_acctbal decimal(15,2) not null,
s_comment varchar(101) not null,
primary key(s_suppkey),
key supplier_fk1 (s_nationkey) ) secondary_engine = rapid;
drop table if exists partsupp;
create table partsupp ( ps_partkey bigint not null,
ps_suppkey bigint not null,
ps_availqty integer not null,
ps_supplycost decimal(15,2) not null,
ps_comment varchar(199) not null,
primary key(ps_partkey,ps_suppkey),
key partsupp_fk1 (ps_suppkey),
key partsupp_fk2 (ps_partkey) ) secondary_engine = rapid;
drop table if exists customer;
create table customer ( c_custkey bigint not null,
c_name varchar(25) not null,
c_address varchar(40) not null,
c_nationkey bigint 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,
primary key(c_custkey),
key customer_fk1 (c_nationkey) ) secondary_engine = rapid;
drop table if exists orders;
create table orders ( o_orderkey bigint not null,
o_custkey bigint 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,
primary key(o_orderkey),
key orders_fk1 (o_custkey) ) secondary_engine = rapid;
drop table if exists lineitem;
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 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,
primary key(l_orderkey,l_linenumber),
key lineitem_fk1 (l_orderkey) ,
key lineitem_fk2 (l_partkey,l_suppkey) ) secondary_engine = rapid;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
上述 SQL 脚本在建表时,同时指定了辅助引擎为 Rapid,便于后续进行 TPC-H 性能测试。
- 并行导入数据
可以利用GreatSQL提供的 并行 LOAD DATA 特性并行导入测试数据,提高导入效率:
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/region.tbl' into table region FIELDS TERMINATED BY '|'; analyze table region;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/nation.tbl' into table nation FIELDS TERMINATED BY '|'; analyze table nation;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/supplier.tbl' into table supplier FIELDS TERMINATED BY '|'; analyze table supplier;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/part.tbl' into table part FIELDS TERMINATED BY '|'; analyze table part;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/customer.tbl' into table customer FIELDS TERMINATED BY '|'; analyze table customer;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/partsupp.tbl' into table partsupp FIELDS TERMINATED BY '|'; analyze table partsupp;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/orders.tbl' into table orders FIELDS TERMINATED BY '|'; analyze table orders;" tpch
$ mysql -f -e "load /*+ SET_VAR(gdb_parallel_load=ON) */ data infile '/data/tpch/data/lineitem.tbl' into table lineitem FIELDS TERMINATED BY '|'; analyze table lineitem;" tpch
2
3
4
5
6
7
8
9
10
11
12
13
14
15
还可以进一步设置并行 LOAD DATA 的并行线程数以及分片大小,详情参考文档:并行 LOAD DATA。
前面提到,可以使用 pdbgen.sh脚本 (opens new window) 生成(多文件多切片式的)测试数据集,因此可以相应地使用 pload.sh脚本 (opens new window) 在已经开启 并行LOAD DATA 的基础上,实现双重并行导入,其效率相对原生的 LOAD DATA 至少可提升数倍。
§ 开始TPC-H测试
在开始测试前,先调低 long_query_time
的值(甚至可以设置为0),使得可以记录所有TPC-H查询测试请求:
# 设置 long_query_time = 1ms
greatsql> set global long_query_time = 0.001;
# 甚至设置为 0,即记录所有请求
#greatsql> set global long_query_time = 0;
2
3
4
5
在前面 4. 生成TPC-H测试查询SQL 中已经生成了测试22个测试查询SQL文件,逐一执行这些查询文件,也可以写个小脚本来执行,并分别记录运行耗时:
$ cat run-thch.sh
#!/bin/bash
workdir=/data/tpch
tpchdb="tpch"
host="172.16.16.10"
port="3306"
user="tpch"
passwd="tpch"
logdir="tpch-runlog-`date +%Y%m%d`"
sleeptime=5
cd ${workdir}
mkdir -p ${logdir}
MYSQL_CLI="mysql -h"${host}" -P"${port}" -u"${user}" -p"${passwd}" -f ${tpchdb}"
# 每个查询SQL执行5遍,其中前2遍是预热
for i in $(seq 1 22)
do
for j in $(seq 1 5)
do
if [ ${j} -le 2 ] ; then
time_1=`date +%s%N`
$MYSQL_CLI < ./queries/tpch_queries_$i.sql > /dev/null 2>&1
time_2=`date +%s%N`
durtime=`echo $time_2 $time_1 | awk '{printf "%0.3f\n", ($1 - $2) / 1000000000}'`
echo "tpch_queries_$i.sql warmup ${j} times END, COST: ${durtime}s"
else
time_1=`date +%s%N`
echo `date '+[%Y-%m-%d %H:%M:%S]'` "BEGIN RUN TPC-H Q${i} ${j} times" >> ./${logdir}/run-tpch-queries.log 2>&1
$MYSQL_CLI < ./queries/tpch_queries_$i.sql >> ./${logdir}/tpch_queries_${i}_${j}.res 2>&1
time_2=`date +%s%N`
durtime=`echo $time_2 $time_1 | awk '{printf "%0.3f\n", ($1 - $2) / 1000000000}'`
echo `date '+[%Y-%m-%d %H:%M:%S]'` "TPC-H Q${i} END, COST: ${durtime}s" >> ./${logdir}/run-tpch-queries.log 2>&1
echo "RUN TPC-H Q${i} ${j} times END, COST: ${durtime}s"
echo "" >> ./${logdir}/run-tpch-queries.log 2>&1
echo "" >> ./${logdir}/run-tpch-queries.log 2>&1
fi
echo "sleeping for ${sleeptime} seconds"
sleep ${sleeptime}
done
done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
这个脚本最新版本可以看这里 TPC-H 自动测试脚本 run-tpch.sh (opens new window)。
在运行查询SQL时,也要观察相关指标:
greatsql> SHOW GLOBAL STATUS LIKE 'Secondary_engine_execution_count';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| Secondary_engine_execution_count | 41 |
+----------------------------------+-------+
2
3
4
5
6
上述结果中的 Secondary_engine_execution_count
状态指标值为 41,表示共发生了 41 次辅助引擎(Rapid)的读取请求。
§ 测试结果
在 GreatSQL 8.0.32-25 中引入了 Rapid 辅助引擎,对 TB 数据量级的 OLAP 复杂数据分析类型查询有很好的优化效果,其查询效率也在不断提升中。
在最近的测试中,利用 Rapid 引擎运行 TPC-H SF100/SF1000 数据量级测试时,总耗时分别为:39.399 和 642.652 秒。
测试数据量 | Q1 | Q2 | Q3 | Q4 | Q5 | Q6 | Q7 | Q8 | Q9 | Q10 | Q11 | Q12 | Q13 | Q14 | Q15 | Q16 | Q17 | Q18 | Q19 | Q20 | Q21 | Q22 | 总耗时 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
TPC-H SF100 | 3.218 | 0.305 | 1.036 | 0.868 | 1.011 | 0.219 | 4.469 | 0.886 | 3.030 | 2.597 | 0.164 | 0.588 | 2.760 | 0.729 | 0.986 | 0.654 | 0.739 | 9.557 | 1.422 | 0.624 | 3.006 | 0.531 | 39.399 |
TPC-H SF1000 | 17.713 | 2.221 | 6.710 | 6.297 | 6.783 | 1.373 | 63.600 | 5.589 | 37.384 | 38.240 | 1.299 | 5.039 | 29.492 | 5.269 | 8.209 | 4.748 | 4.910 | 358.120 | 7.938 | 3.788 | 23.485 | 4.445 | 642.652 |
上述数据的测试机配置为 32C64G、NVMe PCIe SSD 3.8T。
更多关于 GreatSQL 的 TPC-H 测试的详细信息可参考:GreatSQL TPC-H 性能测试报告。
扫码关注微信公众号