CPU Cache掷中率差。一行的多列(字段)数据的内存紧挨在一起,哪怕只对其中的一个字段做操纵,其他字段所占的内存也必要加载进来,这会抢占稀缺的Cache资源。Cache命失会导致被请求的数据从内存加载进Cache,等待内存操纵完成会导致CPU实行指令暂停(Memory Stall),这会增加延时,还可能浪费内存带宽。
变长字段影响计算服从。假设一行包罗int、string、int三列,其中int类型是固定长度,而string是变长的(一般表示为int len + bytes content),变长列的存在会导致无法通过行号算offset做快速定位。
从业界发展情况来看,近几年OLAP引擎发展迅速,该场景追求极致的查询速率,向量化技术在Clickhouse、Doris等Native引擎中得到广泛利用,降本增效的趋势也逐渐扩展到数仓生产。2022年6月DataBricks发表论文《Photon- A Fast Query Engine for Lakehouse Systems》,Photon是DataBricks Runtime中C++实现的向量化实行引擎,相比DBR性能均匀提升4倍,并已应用在Databricks贸易版上,但没有开源。2021年Meta开源Velox,一个C++实现的向量化实行库。2022 Databricks Data & AI Summit 上,Intel 与Kyligence先容了互助开源项目Gluten,旨在为Spark SQL提供Native Vectorized Execution。Gluten+Velox的组合,使Java栈的Spark也可以像Doris、Clickhouse等Native引擎一样发挥向量化实行的性能上风。
从美团内部来看,数仓生产有数万规模计算节点,很多业务决策依靠数据及时产出,若应用向量化实行技术,在不升级硬件的情况下,既可获得可观的资源节省,也能加速作业实行,让业务更快看到数据和做出决策。根据Photon和Gluten的公开数据,应用向量化Spark实行服从至少可以提升一倍,我们在物理机上基于TPC-H测试Gluten+Velox相Spark 3.0也有1.7倍性能提升。
count distinct效果错误。比如这样一条SQL:select A, B, count(distinct userId), sum(amt) from t group by 1,2 ,Gluten会把count(distinct userId) 变为count(userId),通过把userId加到GroupingKey里来实现distinct语义。详细处理惩罚过程如下:
浮点类型转换精度错误。形如查询SELECT concat(col2, cast(max(col1) as string)) FROM (VALUES (CAST(5.08 AS FLOAT), 'abc_')) AS tab(col1, col2) group by col2; 在Spark中返回abc_5.08,在Gluten中返回abc_5.079999923706055。浮点数5.08不能用二进制分数精确表达,近似表示成5.0799999237060546875。Velox通过函数folly::to<std::string>(T val)来实现float类型到string类型的转换,这个函数底层依靠开源库google::double-conversion, folly里默认设置了输出宽度参数DoubleToStringConverter::SHORTEST(可以准确表示double类型的最小宽度),转换时颠末四舍五入之后返回 5.079999923706055。我们把宽度参数改为DoubleToStringConverter::SHORTEST_SINGLE(可以准确表示float类型的最小宽度),转换时颠末四舍五入之后返回 5.08。