seekdb TPC-H 测试
本文介绍如何使用 TPC-H 工具对 seekdb 进行性能测试。
什么是 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版本。 -
TPC-H Tool:点击 下载地址 获取。
-
seekdb:使用服务器模式 seekdb,详细部署操作请参考 通过 yum install 部署 seekdb。
-
部署的 seekdb 所对应的日志盘、clog 盘、data 盘分三块盘,性能级别 PL1,即在启动 seekdb 时,需在
/etc/oceanbase/seekdb.cnf下设置以下参数:port=2881
base-dir=/data/1/seekdb
data-dir=/data/2/seekdb
redo-dir=/data/3/seekdb
测试方案
-
本次测试需使用到 2 台机器,TPC-H 部署在一台机器上。seekdb 部署在另一台机器上,seekdb 的规格为 4C8G,其日志盘、clog 盘、data 盘分三块盘,性能级别 PL1。
-
测试数据量:10G。
使用 TPC-H 工具手动执行 TPC-H 测试
步骤一:获取 seekdb 连接串
mysql -hxx.xx.xx.xx -P2881 -uroot -p**** -A
步骤二:进行环境调优
开始测试前,先要进行 seekdb 调优。请登录 seekdb 并执行以下语句配置相关参数。
ALTER SYSTEM flush plan cache GLOBAL;
ALTER system SET enable_sql_audit=false;
select sleep(5);
ALTER system SET enable_perf_event=false;
ALTER system SET syslog_level='PERF';
alter system set enable_record_trace_log=false;
alter system set data_storage_warning_tolerance_time = '300s';
alter system set _data_storage_io_timeout = '600s';
alter system set trace_log_slow_query_watermark = '7d';
alter system set large_query_threshold='0ms';
alter system set max_syslog_file_count = 300;
alter system set spill_compression_codec = 'lz4';
SET global NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
SET global NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS.FF';
SET global NLS_TIMESTAMP_TZ_FORMAT='YYYY-MM-DD HH24:MI:SS.FF TZR TZD';
set global ob_query_timeout=10800000000;
set global ob_trx_timeout=10000000000;
set global ob_sql_work_area_percentage=50;
alter system set default_table_store_format = 'column' ;
alter system set ob_enable_batched_multi_statement='true';
alter system set _io_read_batch_size = '128k';
alter system set _io_read_redundant_limit_percentage = 50;
SET global parallel_degree_policy = AUTO;
set global parallel_servers_target=10000;
set global collation_connection = utf8mb4_bin;
set global collation_database = utf8mb4_bin;
set global collation_server = utf8mb4_bin;
set global autocommit=1;
alter system set _nested_loop_join_enabled = false;
alter system set ob_enable_batched_multi_statement='true';
步骤三:安装 TPC-H Tool
-
下载 TPC-H Tool。详细信息请参考 TPC-H Tool 下载页面。
-
下载完成后解压文件,进入 TPC-H 解压后的目录。
unzip 7e965ead-8844-4efa-a275-34e35f8ab89b-tpc-h-tool.zip
cd TPC-H\ V3.0.1/ -
复制
makefile.suite。cd dbgen/
cp makefile.suite Makefile -
修改
Makefile文件中的CC、DATABASE、MACHINE、WORKLOAD等参数定义。vim MakefileCC = 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文件,并添加新的宏定义。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 -
编译文件。
make返回结果如下:
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o build.o build.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o driver.o driver.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o bm_utils.o bm_utils.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o rnd.o rnd.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o print.o print.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o load_stub.o load_stub.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o bcd2.o bcd2.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o speed_seed.o speed_seed.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o text.o text.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o permute.o permute.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o rng64.o rng64.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -O -o dbgen build.o driver.o bm_utils.o rnd.o print.o load_stub.o bcd2.o speed_seed.o text.o permute.o rng64.o -lm
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o qgen.o qgen.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -c -o varsub.o varsub.c
gcc -g -DDBNAME=\"dss\" -DLINUX -DMYSQL -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64 -O -o qgen build.o bm_utils.o qgen.o rnd.o varsub.o text.o bcd2.o permute.o speed_seed.o rng64.o -lm会生成后续生成数据的 dbgen 文件和生成 sql 的 qgen、dists.dss 文件。
步骤四:生成数据
您可以根据实际环境生成 TPC-H 10G 或者 1G 数据。本文以生成 10G 数据为例。
./dbgen -s 10
mkdir tpch10
mv *.tbl tpch10
步骤五:生成查询 SQL
您可参考本节中的下述步骤生成查询 SQL 后进行调整,也可直接使用 GitHub 中给出的查询 SQL。若您选择使用 GitHub 中的查询 SQL,您需将 SQL 语句中的 cpu_num 修改为 4 并发数 。
使用 TCP-H 自带工具生成,步骤如下:
-
将
dbgen/qgen、dbgen/dists.dss和queries拷贝到mysql_sql文件夹下。mkdir mysql_sql
cp qgen mysql_sql/
cp dists.dss mysql_sql/
cp queries/*.sql mysql_sql/ -
在
mysql_sql文件夹下创建gen.sh脚本生成查询 SQL。vim gen.sh#!/usr/bin/bash
for i in {1..22}
do
./qgen -d $i -s 10 > db"$i".sql
done -
执行
gen.sh脚本。sh gen.sh -
调整查询 SQL 。
dos2unix *调整后的查询 SQL 请参考 GitHub。
-
修改查询 SQL 的并发数。
以
Q1为例,修改后的 SQL 语句如下:SELECT /*+ parallel(4) */ ---增加 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
GROUP BY
l_returnflag,
l_linestatus
ORDER BY
l_returnflag,
l_linestatus;
步骤六:新建表
创建表结构文件 create_tpch_mysql_table_part.ddl。
DROP TABLE IF EXISTS LINEITEM;
CREATE TABLE lineitem (
l_orderkey int(11) NOT NULL,
l_partkey int(11) NOT NULL,
l_suppkey int(11) NOT NULL,
l_linenumber int(11) 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) 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 varchar(25) DEFAULT NULL,
l_shipmode varchar(10) DEFAULT NULL,
l_comment varchar(44) DEFAULT NULL,
primary key(l_shipdate, l_orderkey, l_linenumber)
)row_format = condensed
partition by key (l_orderkey) partitions 32 with column group(each column);
alter table lineitem CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS ORDERS;
CREATE TABLE orders (
o_orderkey int(11) NOT NULL,
o_custkey int(11) NOT NULL,
o_orderstatus varchar(1) DEFAULT NULL,
o_totalprice decimal(15,2) DEFAULT NULL,
o_orderdate date NOT NULL,
o_orderpriority varchar(15) DEFAULT NULL,
o_clerk varchar(15) DEFAULT NULL,
o_shippriority int(11) DEFAULT NULL,
o_comment varchar(79) DEFAULT NULL,
PRIMARY KEY (o_orderkey, o_orderdate)
) row_format = condensed
partition by key(o_orderkey) partitions 32 with column group(each column);
alter table orders CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS PARTSUPP;
CREATE TABLE partsupp (
ps_partkey int(11) NOT NULL,
ps_suppkey int(11) NOT NULL,
ps_availqty int(11) DEFAULT NULL,
ps_supplycost decimal(15,2) DEFAULT NULL,
ps_comment varchar(199) DEFAULT NULL,
PRIMARY KEY (ps_partkey, ps_suppkey)) row_format = condensed
partition by key(ps_partkey) partitions 32 with column group(each column);
alter table partsupp CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS PART;
CREATE TABLE part (
p_partkey int(11) NOT NULL,
p_name varchar(55) DEFAULT NULL,
p_mfgr varchar(25) DEFAULT NULL,
p_brand varchar(10) DEFAULT NULL,
p_type varchar(25) DEFAULT NULL,
p_size int(11) DEFAULT NULL,
p_container varchar(10) DEFAULT NULL,
p_retailprice decimal(12,2) DEFAULT NULL,
p_comment varchar(23) DEFAULT NULL,
PRIMARY KEY (p_partkey)) row_format = condensed
partition by key(p_partkey) partitions 32 with column group(each column);
alter table part CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS CUSTOMER;
CREATE TABLE customer (
c_custkey int(11) NOT NULL,
c_name varchar(25) DEFAULT NULL,
c_address varchar(40) DEFAULT NULL,
c_nationkey int(11) DEFAULT NULL,
c_phone varchar(15) DEFAULT NULL,
c_acctbal decimal(15,2) DEFAULT NULL,
c_mktsegment char(10) DEFAULT NULL,
c_comment varchar(117) DEFAULT NULL,
PRIMARY KEY (c_custkey)) row_format = condensed
partition by key(c_custkey) partitions 32 with column group(each column);
alter table customer CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS SUPPLIER;
CREATE TABLE supplier (
s_suppkey int(11) NOT NULL,
s_name varchar(25) DEFAULT NULL,
s_address varchar(40) DEFAULT NULL,
s_nationkey int(11) DEFAULT NULL,
s_phone varchar(15) DEFAULT NULL,
s_acctbal decimal(15,2) DEFAULT NULL,
s_comment varchar(101) DEFAULT NULL,
PRIMARY KEY (s_suppkey)
) row_format = condensed partition by key(s_suppkey) partitions 32 with column group(each column);
alter table supplier CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS NATION;
CREATE TABLE nation (
n_nationkey int(11) NOT NULL,
n_name varchar(25) DEFAULT NULL,
n_regionkey int(11) DEFAULT NULL,
n_comment varchar(152) DEFAULT NULL,
PRIMARY KEY (n_nationkey)
) row_format = condensed with column group(each column);
alter table nation CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
DROP TABLE IF EXISTS REGION;
CREATE TABLE region (
r_regionkey int(11) NOT NULL,
r_name varchar(25) DEFAULT NULL,
r_comment varchar(152) DEFAULT NULL,
PRIMARY KEY (r_regionkey)
) row_format = condensed with column group(each column);
alter table region CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE VIEW revenue0 AS
SELECT l_suppkey as supplier_no,
SUM(l_extendedprice * ( 1 - l_discount )) as total_revenue
FROM lineitem
WHERE l_shipdate >= DATE '1996-01-01'
AND l_shipdate < DATE '1996-04-01'
GROUP BY l_suppkey;
步骤七:加载数据
您可以根据上述步骤生成的数据和 SQL 自行 编写脚本。加载数据示例操作如下:
-
创建加载脚本目录。
mkdir load
cd load
cp xx/create_tpch_mysql_table_part.ddl xx/tpch10/ -
创建加载数据的脚本
load.py。#!/usr/bin/env python
#-*- encoding:utf-8 -*-
import os
import sys
import time
import commands
hostname='$host_ip' # 注意!!请填写 seekdb 所在服务器的 IP 地址
port='$host_port' # seekdb 的端口号
user='$user' # 用户名
password='$password' # 密码
data_path='$path' # 注意!!请填写 seekdb 所在服务器下 tbl 所在目录
db_name='$db_name' # 数据库名
# 创建表
cmd_str='mysql -h%s -P%s -u%s -p%s -D%s < create_tpch_mysql_table_part.ddl'%(hostname,port,user,password,db_name)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str='mysql -h%s -P%s -u%s -p%s -D%s -e "show tables;" '%(hostname,port,user,password,db_name)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/customer.tbl' into table customer fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/lineitem.tbl' into table lineitem fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/nation.tbl' into table nation fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/orders.tbl' into table orders fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -D%s -e "load data /*+ parallel(16) */ infile '%s/partsupp.tbl' into table partsupp fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/part.tbl' into table part fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/region.tbl' into table region fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result
cmd_str=""" mysql -h%s -P%s -u%s -p%s -c -D%s -e "load data /*+ parallel(16) */ infile '%s/supplier.tbl' into table supplier fields terminated by '|';" """ %(hostname,port,user,password,db_name,data_path)
result = commands.getstatusoutput(cmd_str)
print result -
加载数据。
python load.py返回结果如下:
(0, '')
(0, 'Tables_in_test\ncustomer\nlineitem\nnation\norders\npart\npartsupp\nregion\nrevenue0\nsupplier')
(0, '')
(0, '')
(0, '')
(0, '')
(0, '')
(0, '')
(0, '')
(0, '')加载完数据后需进行合并和统计信息。
-
执行合并。
连接 seekdb 执行以下语句进行合并。
ALTER SYSTEM MAJOR FREEZE; -
查看合并是否完成。
SELECT FROZEN_SCN, LAST_SCN
FROM oceanbase.CDB_OB_MAJOR_COMPACTION;信息所有的
FROZEN_SCN和LAST_SCN的值相等即表示合并完成。 -
执行收集统计信息。
创建收集统计信息文件
analyze_table.sql。call dbms_stats.gather_table_stats(NULL, 'part', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');
call dbms_stats.gather_table_stats(NULL, 'lineitem', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');
call dbms_stats.gather_table_stats(NULL, 'customer', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');
call dbms_stats.gather_table_stats(NULL, 'orders', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');
call dbms_stats.gather_table_stats(NULL, 'partsupp', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');
call dbms_stats.gather_table_stats(NULL, 'supplier', degree=>128, granularity=>'AUTO', method_opt=>'FOR ALL COLUMNS SIZE 128');登录 seekdb,执行以下语句进行收集统计信息:
source analyze_table.sql
步骤八:执行测试
您可以根据上述步骤生成的数据和 SQL 自行编写脚本。执行测试示例操作如下:
-
编写测试脚本
tpch.sh。#!/bin/bash
TPCH_TEST="mysql -h $host_ip -P $host_port -uroot -Dtest -p $password -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 -
执行测试脚本。
sh tpch.sh
说明
测试结果可参考 seekdb TPC-H 测试报告。
FAQ
-
导入数据失败。报错信息如下:
ERROR 1017 (HY000) at line 1: File not existtbl文件必须放在所连接的 seekdb 所在机器的某个目录下,因为加载数据必须本地导入。 -
导入数据报错。报错信息如下:
ERROR 1227 (42501) at line 1: Access denied需要授予用户访问权限。运行以下命令,授予权限:
grant file on *.* to tpch_100g_part;