TPC-H深入剖析 part2 Quantifying TPC-H Choke Points and Their Optimizations

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 这篇承接了上一篇对于TPC-H中chockpoint的定性分析,基于Hyrise这个学术系统进行了较为孤立且细致的量化分析,并给出了不同类型chokepoint优化对于TPCH query的相对影响。TPC-H的chokepoints在上一篇已详细介绍,并介绍了MySQL和PolarDB的对应优化情况。

这篇承接了上一篇对于TPC-H中chockpoint的定性分析,基于Hyrise这个学术系统进行了较为孤立且细致的量化分析,并给出了不同类型chokepoint优化对于TPCH query的相对影响。

TPC-H的chokepoints在上一篇已详细介绍,并介绍了MySQL和PolarDB的对应优化情况。

基本介绍

这篇paper的一些主要工作是:

  1. 基于之前paper提出的若干chokepoints,选取其中11条进行了量化分析,之所以选择它们是因为这些都是logical的优化,和具体的execution engine/execution scheduler没有关系,因此建议将更加普适。
  2. 基于Hyrise系统进行改造,从而可以在同等条件下,打开/关闭优化code,尽可能isolated的去测试每一个优化点。
  3. 提出了2个之前没有列出的优化点: semi-join reduction / between composition

paper中对于choke point的分类方式与前篇 有所不同,是按照影响的范围 + 逻辑/物理优化来分类的:

  • plan-level,通过改变plan structure,尽早的减少table cardinality,从整体上提升性能。join ordering / predicates pushdown / flatten of subquery … 都属于这类
  • operator-level,只针对个别算子做局部逻辑优化,例如dependent group-by key消除
  • Implementation-specific,和具体物理实现相关,Bloom-filter / SIMD / compressed execution 属于这类

这篇paper主要关注前两种。

Hyrise

Hyrise 是由Hasso-Plattner-Institute开发的一款in-memory列存DBMS,其基本特点是

  • 存储

table被水平切分为Chunk(类似morsel),而且也是10万行,Chunk是执行+压缩+统计信息的基本单位。

Chunk中按列存储+压缩,每列对应一个segment,内部做dictionary压缩,包含的统计信息有equi-height histogram + zonemap。静态数据是只读的,整体组织为main store + append only delta store,MVCC作为Concurrent Control机制。

优化:

有rule-based + cardinality(cost)-based,cardinality估计基于统计信息

执行:

table scan使用了AVX512 SIMD来加速

join使用了1-pass radix partitioned hash join (SIMD)

aggregation使用了hash-aggregation(SIMD)

Plan level optimization

Join Ordering

由于TPCH数据分布非常理想化,即使很简单的基于greedy search的join ordering算法 + 基本的统计信息(MIN/MAX/NDV/Cardinality),也经常可以取得不错的效果,因此使用更优算法(DPccp)提升并不大。可以认为TPCH不是很适合做join ordering的benchmark。可以考虑更复杂的TPCDS。

image.png

可以看到,除了Q7外,其余几条join order在DPccp和一个简单的greedy join算法下产生了相同结果。

Predicate Pushdown and Ordering

将谓词尽可能沿算子树下推,几乎总是可以通过尽早过滤数据取得更好的效果。

谓词排序则可以采用静态/动态两种方式,静态可以基于选择率,而动态则基于执行中收集的准确的统计信息,此外也应考虑谓词evaluation本身的代价。

image.png

Between composition

这个只是将xx > thresh1 AND xx <= thresh2 改写为一个xx bewtween[thresh1, thresh2]。通过把多个range谓词组合成一个between谓词,减少谓词算子的数量,同时生成了更为严格的过滤条件。

v2-e40c87d60395359b55e4c53b3dff0548_b.png

Join-Dependent Predicate Duplication

理论上对于涉及到多表,但不是Join cond的复杂谓词,必须要在join完成后才能计算(SES约束),但其实有个优化技巧,就是提取其中可以下推到单表的条件(顶层AND中的子条件),然后下推,当然原始条件仍然保留在join之上,只是尽可能做一下提前过滤。例如Q7中的

(n1.n_name = 'SAUDI ARABIA' and n2.n_name = 'ARGENTINA') 
or 
(n1.n_name = 'ARGENTINA' and n2.n_name = 'SAUDI ARABIA')

这个where条件,由于n1/n2都是nation表,其实可以抽取出n_name = 'SAUDI ARABIA' OR n_name = 'ARGENTINA' 下推到n1/n2两个nation表的单表上,做提前过滤。

这个小型优化其实并不复杂,只要可以辨识OR的子条件引用同一个table即可。

v2-80789e1d7fe73038730bf185535670f6_b.png

Physical Locality

通过利用Clustered index key的有序性,以及datetime列的相关性,可以做几件事

  1. 利用NL join,即使join key不是datetime,对于TPCH的数据语义,也可以获取大体上的数据locality
  2. 基于列相关性,建立range谓词的传递,这个也是和TPCH的数据语义相关的
  3. 建立range partition,做partition pruning,减少数据量

这个优化感觉主要利用了TPC-H特定的语义,没有什么通用性?欢迎大家给我些指教。。

Correlated Columns

和上一条优化是类似的思路,仍然是利用相关列数据的聚簇属性来做优化。

Flatten Subqueries

这个是TPCH workload中最大的性能优化点,基本思路就是把相关表/列下压到subquery中,从而在内层引入外层相关列的所有value,物化成非相关表,再与外层表用相关条件做join。这种unnesting,外层table行数越多,收益越大。

image.png

Semi-join reduction

这也是本篇paper提出的一个新优化思路,在外层相关表有很好的过滤条件时可以应用,基本思路是由于外层表已经过滤掉了很多数据,在外层解相关后,可以把这种过滤性传递到内层,这个和CP5.2 Moving predicates into Subquery思路有些类似。

image.png

可以看到对Q17,在外层相关条件上拉后,通过进一步将外表推入内层做SEMI JOIN,可以大量减少lineitem表做aggregation的行数。

由于semi-join本身也有代价,这种优化是否有收益,是比较难以确定的,概略来看,外层表过滤性越好,收益越大。从变换的实现角度,由于semi-join是基于相关表 + 相关列,已经在unnesting时识别出来了,而且semi-join是一种过滤的语义不影响已有的join order,因此还是比较简单。

image.png

Subplan Reuse

感觉这个比较困难,需要确定两个subplan tree是否相同,此外reuse是否有收益不好评估,因为可能为了追求common part,其中一个plan本来更高效却放弃掉了。

如果可以提取出common subplan,需要转换为同一个physical operator,被后续多个算子使用。例如Q15的revenue view,可以一次性物化后,在谓词计算和join时共享物化结果。

image.png

Result Reuse

实验显示,对整个query result的cache在TPCH中没有明显收益,还会占用大量内存,因为大部分query parameter变化很大,导致很难精确匹配。

Logical operator level optimization

Dependent Group-By Keys

除了之前提到的常规的functional dependency以外,还有种特定情况下的优化可以做:

如果group by key就是unique key,而且是复杂类型(比如string),可以替换为更简单的类型(比如主键)来进行计算。

Large IN Clauses

在Q12/Q16/Q19/Q22中都是要了IN谓词,但其中value数量都是比较少的,通常来说,如果不使用expression JIT,则有3种计算方式

  1. 原始的解析执行,依次计算 + 比较,这样其实最为灵活,但大量分支加类型比较等会带来高昂的解析成本,降低性能。
  2. 转为disjunction,每个value变为一个子条件独立求值,最后将结果merge。这种方式适合少量value且仅引入单列的in-list。
  3. 通过semi hash join来计算,这个比较高效且能较好处理大量value,但其前提要求所有value具有相同类型。

image.png

上图展示了3种策略在不同IN-list大小下的执行性能,以及Hyrise自适应执行策略的结果。可以看到,只有在value非常少时( < 3 ),转为OR是有优势的,而当value很多时,semi hash join更有优势。如果可以根据IN-list大小/类型等智能选择策略,是最优的。

结论

总体来说,subquery flatten + predicates pushdown and ordering对于TPCH具有最大的影响。不同的优化在不同的query上产生的效果差异很大,有的query能优化几个数量级,有的则没有明显变化。

通过本篇paper的量化比较,可以对优化器的开发工作给与一定引导,为不同的工作任务指定适当的优先级。

此外,客观来看,TPCH benchmark虽然仍很流行,但它有一些明显的缺点:

  • 数据过于理想,基本满足了uniform + independent + join inclusive这几个cardinality estimation的基本假设,因此并不适合做针对CE的评估,而更适合于评估其他优化机制。
  • 随着数据+业务系统的越发复杂,其query已经显得过于简单了,如果想更广泛的测试optimizer的能力,可以考虑使用TPC-DS。
目录
相关文章
|
6月前
|
分布式计算 测试技术 Apache
Apache Hudi vs Delta Lake:透明TPC-DS Lakehouse性能基准
Apache Hudi vs Delta Lake:透明TPC-DS Lakehouse性能基准
117 4
|
6月前
|
存储 缓存 算法
TPC-H
TPC-H是世界上最为流行的OLAP workload的benchmark程序,被广泛应用于评估查询处理过程的相关任务。作为一款在线分析处理基准程序,TPC-H模拟了供应商和采购商之间的交易行为,包含针对8张表的22条分析型查询。在TPC-H的测试中,主要关注两个指标:Power单并发测试和Throughput多并发测试。
85 6
|
SQL 存储 分布式计算
Spark做TPC-DS性能测试
Spark做TPC-DS性能测试
1034 0
|
Oracle 关系型数据库 Unix
TPC-C相关
TPC-C相关
208 0
|
SQL HIVE C++
Hive - Count && Sum 使用与性能对比
使用 hive 计数时常使用 Count 和 Sum 两个函数进行统计,下面看看二者的使用方法。
677 0
Hive - Count && Sum 使用与性能对比
|
分布式计算 关系型数据库 MySQL
测试TPC-DS的性能提升
测试TPC-DS的性能提升
339 0
|
SQL 分布式计算 大数据
【spark系列3】spark 3.0.1 AQE(Adaptive Query Exection)分析(一)
【spark系列3】spark 3.0.1 AQE(Adaptive Query Exection)分析(一)
679 0
【spark系列3】spark 3.0.1 AQE(Adaptive Query Exection)分析(一)
|
分布式计算 Spark
【spark系列3】spark 3.0.1 AQE(Adaptive Query Exection)分析(二)
【spark系列3】spark 3.0.1 AQE(Adaptive Query Exection)分析(二)
439 0