TPC-H简介
TPC-H是一套针对数据库决策支持能力的测试基准,通过模拟数据库中与业务相关的复杂查询和并行的数据修改操作考察数据库的综合处理能力,获取数据库操作的响应时间和每小时执行的查询数指标(QphH@Size)。
TPC-H基准模型涉及22条复杂的select查询流语句和2条带有insert和delete程序段的更新流语句。测试分为Power测试和Throughout测试两种类型,Power测试是随机执行22条查询流中的一条测试流和2条更新流中的一条测试流,考核指标为QppH@Size;Throughout测试执行的是多条查询流和一条更新流对数据库的混合操作,考核指标是QthH@Size,Power测试和Throughout测试通过数理方式合成的结果为TPC-H基准测试中最关键的一项指标:每小时数据库查询数(QphH@Size),是QppH@Size和QthH@Size结果的乘积的1/2次方。
一、TPC-H模型概述
-
设计遵照数据库设计三范式(3-NF):
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。
第二范式(2NF):第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
第三范式(3NF):第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。 -
TPC-H评价数据库哪方面。
TPC- H 主要目的是评价特定查询的决策支持能力,强调服务器在数据挖掘、分析处理方面的能力。通过模拟零售商市场分析,构建一个数据仓库。 -
TPC-H表关系:
包含8个基本关系表part、region、nation、customer、supplier、orders、partsupp、lineitem,其中:
Nation和Region的记录数是固定的,分别为25条和5条记录。
其它6个表的记录数随着比例因子SF(Scale Factor)的增加而增加,SF共有8个档位1、10、30、100、300、1000、3000、10000,1SF对应1GB单位,SF规定的只是基础数据量,并不包括索引和临时表。 -
TPC-H基准测试包括了22个SQL语句随机组成的查询流。
-
两个更新(带有insert和delete的程序段)操作组成一个更新流,查询流和更新流并发执行,查询流数目随数据量的增加而增加。
-
TPC规范下载地址:(TPC官网)
https://tpc.org/tpc_documents_current_versions/current_specifications5.asp
TPC-H中文规范:
https://max.book118.com/html/2019/0318/8076114032002013.shtm
二、TPC-H评价指标
TPC-H的主要评价指标:
- TPC-H模型的主要评价指标为:各个查询的相应时间。
TPC-H主要有三个度量标准:
- TPC-H的性能度量:每小时合成查询度量(QphH@size)。
数字值TPC-H功率和TPC-H吞吐量结合形成TPC-H合成的每小时查询性能测试,算式如下:
QphH@Size为每小时查询量*比例因子(SF),计算到小数点后一位,精确到0.1。
size表示数据库规模的大小,反映系统在处理查询时的能力。
-
价格/性能度量:TPC-H S/QphH。
即已选数据库规模下TPC-H每个QphH价格@规模,使用QphH@规模的算式可参考规范… -
系统可获得日期。
三、TPC-H 表介绍
TPC-H共包含八个表:part、region、nation、customer、supplier、orders、partsupp和lineitem。
part:表示零件的信息。
supplier:表示供货商的信息。
partsupp:表示供货商的零件的信息。
customer:表示顾客的信息。
orders:表示订单的信息。
lineitem:表示在线商品的信息。
nation:表示国家的信息。
region:表示地区的信息。
他们之间的关系是(官方文档给出):
PS:八个表的主键与外键均在规范有详细规定,具体请参考规范不再赘述。
四、TPC-H Refresh函数介绍及实现
总的来说,TPC-H测试分成两个部分:
- Query:Power Run,Throughput Run。即功耗测试和吞吐量测试。
- Modify:RF1,RF2。即插入和删除的更新操作。
更新函数的定义如下:
A refresh stream is defined as the sequential execution of an integral number of pairs of refresh functions submit-ted from within a batch program.
一个更新流定义为 由一个批处理程序提交的整数对更新函数的 顺序执行。
Note:更新函数分为RF1,RF2两个操作,一个更新流需要由一个包含这两个操作的脚本共同提交,并按照某一顺序执行,以确定不同的查询操作中数据库的数据总量不变。
更新函数的刷新比例定义如下:
The refresh data set, which defines the set of rows to be inserted or deleted by each execution of the refresh function into or from the ORDERS and LINEITEM tables. This set of rows represents 0.1% of the initial population of these two tables.
更新数据设置,定义通过在orders表和lineitem表上执行更新函数时所产生的插入行或删除行,这些行占两个表初始总量的0.1%。
更新函数的事务要求
- 满足所有ACID性质
- 每个原子事务都包含足够数量的数据更改以保持数据库的逻辑一致性。例如增加或删除一个新订单,lineitem表和orders表要在相同事物内都被更改。
- 更新函数最后一个事务成功完成时发送一个输出消息。
Note:要满足业务层的一致性。从orders表删除一个订单时,lineitem中对应的数据也要在该事务中删除。
更新函数的实现
规范没有对刷新功能的实现提出任何要求,除了刷新功能定义的功能等效性和合规性。仅对于RF1和RF2,允许实施:
•使用任何语言编写刷新功能的代码;
•在测量间隔之前或期间的任何时间,对SUT上的可执行代码进行预处理、编译和链接。
•在执行基准测试之前,向SUT提供RF1插入的行或RF2删除的行的’set of key’。
Note:目的是要将更新操作所需要的数据资源同查询所需要的数据资源分隔开。
•将各个刷新函数分组到事务中,并以串行或并行方式组织它们的执行。在功率测试和吞吐量测试中,该分组可能不同。
PS:对于更新函数操作,中文资料比较少,因此我将规范中比较重要的原文摘录下来以供学习,后面也给出我更新操作的手法。
五、实战
TPC-H测试最好用到dbgen和qgen两个工具,这里只简要介绍其用法,有兴趣了解的同学可以去github上参阅。搜索dbgen即可
初始化数据库与建库建表操作不再赘述。
我另外多建立了add_lineitem;add_orders和delete_orders三个表用来做更新操作的数据仓,其主键和外键与lineitem、orders表相同即可。
cp makefile.suite makefile
sed -i "s/CC\W*=/CC = gcc/g" makefile
sed -i "s/DATABASE\W*=/DATABASE = SQLSERVER/g" makefile
sed -i "s/MACHINE\W*=/MACHINE = LINUX/g" makefile
sed -i "s/WORKLOAD\W*=/WORKLOAD = TPCH/g" makefile
make clean
make
//生成dbgen和qgen两个可执行程序。
./dbgen -s 1 //生成SF=1的数据文件
./dbgen -s 1 -U 22 //生成SF=1的22份更新操作文件
导入数据,在此提示若在本地对数据库进行操作MySQL及其分支是不允许本地操作数据的,有以下两种解决办法:
报错:Loading local data is disabled; this must be enabled on both the client and server sides.
//解决方法: [1] 登录mysql时:
mysql --local-infile=1 -u root;
[2] 设置客户端加载功能:
set global local_infile = 1;
以上两种方法选其一,设置好后使用
show global variables like 'local_infile';
查看变量,若出现:
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| local_infile | ON |
+----------------------+----------+
就OK了。
PS:需要按以下顺序导入表,region,nation,part,supplier,partsupp,customer,orders,lineitem.
cd queries
cp ../qgen .
cp ../dists.dss . //将可执行文件qgen和字典复制到queries目录下
for line in {1..22} //创建22个查询操作语句
do
sed -i “/^:n.*/d” $line.sql //” ”的使用要注意用英文格式
./qgen -d $line > d$line.sql //生成的语句用d做前缀
done
在数据库中执行:
source ./d1.sql
这样就可以查询d1条查询语句了。当然,你进入数据库的目录里要有这条sql,不然就用绝对地址。
六、更新操作的实现
我实现更新操作是分开加载数据和增删操作的,这样可以更准确的统计更新操作的用时(规范里更新操作时间不包括数据的加载)。而且可以保证事务的原子性(也是规范里明确要求的)。当然,我选择的是每执行一次查询操作就走一边更新流,也可以选择一次走完,改变dbgen的-U参数为1即可。
load.sql
--make sure the table is empty
truncate table delete_orders;
truncate table add_orders;
truncate table add_lineitem;
--load updata to the tmp table
LOAD DATA LOCAL INFILE '/home/greatsql-tpch/savedata/delete.1' INTO TABLE delete_orders FIELDS TERMINATED BY '|';
LOAD DATA LOCAL INFILE '/home/greatsql-tpch/savedata/orders.tbl.u1' INTO TABLE add_orders FIELDS TERMINATED BY '|' lines terminated by '|\n';
LOAD DATA LOCAL INFILE '/home/greatsql-tpch/savedata/lineitem.tbl.u1' INTO TABLE add_lineitem FIELDS TERMINATED BY '|' lines terminated by '|\n';
RF.sql
--insert data
begin;
insert into orders select * from add_orders;
insert into lineitem select * from add_lineitem;
--remove data
begin;
delete from lineitem where l_orderkey in (select o_orderkey from delete_orders);
delete from orders where o_orderkey in (select o_orderkey from delete_orders);
七、致谢
非常感谢这些博主的精彩文章,给了我很大帮助:
TPC-H Refresh Function 规范分析-余璜的技术博客
TPCH模型规范及测试说明