作者:陆路,花名世仪,阿里巴巴计算平台事业部EMR团队高级开发工程师,大数据领域技术爱好者,对Spark、Hive等有浓厚兴趣和一定的了解,目前主要专注于EMR产品中开源计算引擎的优化工作。
背景介绍
TPC-DS 测试集采用星型和雪花型等多维数据模型,包含 7 张事实表和 17 张维度表,以 store channel 为例,事实表和维度表的关联关系如下所示:
分析 TPC-DS 全部 99 个查询语句不难发现,绝大部分语句的过滤条件都不是直接作用于事实表,而是通过过滤维度表并将结果集与事实表 join 来间接完成。因此,优化器很难直接利用事实表索引来减少数据扫描量。如何利用好查询执行时的维度表过滤信息,并将这些信息下推至存储层来完成事实表的过滤,对于性能提升至关重要。
在 2019 年的打榜测试中,我们基于 Spark SQL Catalyst Optimizer 开发的 RuntimeFilter 优化 对于 10TB 数据 99 query 的整体性能达到 35% 左右的提升。简单来说,RuntimeFilter 包括两点核心优化:
动态分区裁剪:事实表以日期列(date_sk)为分区列建表,当事实表与 date_dim 表 join 时,optimizer 在运行时收集 date_dim 过滤结果集的所有 date_sk 取值,并在扫描事实表前过滤掉所有未命中的分区文件。
非分区列动态过滤:当事实表与维度表的 join 列为非分区列时,optimizer 动态构建和收集维度表结果集中 join 列的 Min-Max Range 或 BloomFilter,并在扫描事实表时下推至存储层,利用存储层索引(如 Parquet、ORCFile 的 zone map 索引)来减少扫描数据量。
问题分析
为了进一步挖掘 RuntimeFilter 优化的潜力,我们选取了部分执行时间较长的 query 进行了细致的性能剖析。这些 query 均包含大于一个事实表和多个维度表的复杂 join。在分析了 RuntimeFilter 对各个 query 的性能提升效果后,我们发现:
动态分区裁剪的性能提升效果明显,但很难有进一步的优化空间
非分区列动态过滤对整体提升贡献相比分区裁剪小很多,主要是因为很多下推至存储层的过滤条件并没有达到索引扫描的效果
聪明的同学应该已经发现,只有 date_dim 这一张维度表和分区列相关,那么所有与其它维度表的 join 查询从 RuntimeFilter 优化中受益都较为有限。对于这种情况,我们做了进一步的