PG 向量化引擎
向量化引擎是OLAP提高数据库性能的有效技术。PostgreSQL电子邮件列表讨论了向量化引擎。以下是分析。
代码位于https://github.com/zhangh43/vectorize_engine,并且合入了PG13中。其基本思想是扩展TupleTableSlot,引入VectorTupleTableSlot(由投影列组织的列数组)。每列数组在内存中连续。这使得表达式计算可以很好地使用缓存和缓存SIMD。我们已经重构了SeqScanNode和AggNode,目前支持VectorTupleTableSlot。
以下是我们设计的特点:
1)纯扩展。不会解码任何代码PG内核中
2)CustomScan节点。我们使用CustomScan框架替换原始执行器节点,如SeqScan、Agg等。基于CustomScan,我们可以扩展CustomScanState、BeginCustomScan()、ExecCustomScan()、EndCustomScan接口实现向量化执行逻辑。
3)Post planner hook。产生Plan后,使用plan_tree_walker来源执行计划树,检测能否量化。如果可以,则使用向量化节点(CustomScan替换非向量化节点(如节点形式)SeqScan、Agg等)。如果没有,将其转换为原始执行计划,并使用非向量化执行器。这部分将在未来得到改进。例如,当一些节点不能量化时,它们将不再转换为原始执行计划,而是使用它们Batch/UnBatch将节点与向量化和非向量化节点兼容。
4)支持逐步实现新的向量化执行节点。目前只支持向量化SeqScan和Agg,但打开向量化插件后,其他包括Join查询也可以执行。
5)继承原始执行器代码。我们选择了更平滑的方式来改变当前的情况PG并量化执行器节点,而不是重写整个执行器。复制当前执行器node基于此,向量化逻辑被添加到我们的扩展中。PG在改进执行器时,我们可以很容易地将其合并到我们的插件中。我们想知道通过扩展实现向量化执行器是否是一个好方法?
6)可拔插存储。PG现在已支持可拔插存储了。TupleTableSlot抽象为重构TupleTableSlotOps结构。当我们将PG升级到最新版本时,VectorTupleTableslot升级可以基于此框架完成。
我们执行TPCH(10G)benchmark,Q1结果对比:PG是50s,向量化PG是28s。可通过以下方法提高性能:
1)heap tuple解码占用更多CPU资源。我们将在未来使用它。zedstore,向量化执行器更适合列存。
2)向量化agg并未完全向量化。我们还需要做很多优化。例如,批量计算hash值,优化x向量化HashAgg的hash表
3)将Datum转化为真实类型和反操作的成本都很高,比如DatumGetFloat4 & Float4GetDatum。优化方法是VectorTupleSlot真实类型直接存储在中间,而不是datums的数组。
相关工作:
1)VOPS也是向量化执行插件:https://github.com/postgrespro/vops.
2)Citus向量化执行器:https://github.com/citusdata/postgres_vectorization_test。它使用ExecutorRun_hook使用向量化执行器运行cstorefdw支持列存储。
请注意,目前的向量化执行器是基于PG9.但是,可以通过一些努力移植到master/zedstore。当我们朝着这个方向前进时,我们非常感谢我们收到的反馈。
我认为向量化执行器是对的PG来说是绝对必要的,特别是考虑下到现在我们由列存原型zedstore。我们绝对需要一个向量化执行器来充分利用列存的优点。
然而,我不完全理解为什么建议扩展它。是的。自定义节点不受影响PG提供向量化执行。但为了高效继承zedstore我们需要扩展向量化执行器table-AM(VectorTupleTableSlot以及相应的扫描函数)。当然,扩展向量化执行器更容易,但我认为迟早应该添加到PG内核中。
据我所知,你已经通过一些原型实现了(否则你是如何获得性能结果的?)如果是这样,你打算发布它,还是你认为你应该从零开始开发执行器?
:
原型扩展位置https://github.com/zhangh43/vectorize_engine。同意在某一天向量化执行器添加向量化执行器PG内核中。但是这么大的特点不仅需要改变table-AM,例如,每个执行器节点都需要改变,Agg,Join,Sort节点等。以及表达式计算函数和聚合transition函数、combine函数等。我们还需要量化方向。因此第一步作为一个插件来完成,如果在社区中流行并且稳定下来,我们随时可以合入PG内核中。
我们真的希望从社区得到一些关于CustomScan的反馈。CustomScan只是抽象层。扫描节点通常用于支持用户定义。但其他一些PG扩展(pgstorm)它已被用作通用CustomNode,例如Agg,Join等。由于向量化引擎需要支持所有节点的向量化处理,我们选择遵循上述想法CustomScan。
基于VOPS一些经验担忧:
1)量化模型(列式)性能对某些类型的查询具有优势,但对其他类型的查询效率较低。此外,数据以行形式导入数据库。一行插入列存效率很低。因此,在导入列存之前,需要一些批量导入工具来缓冲插入数据。这实际上是数据模型而不是向量化执行器的问题。但我想在这里表达的是,最好同时拥有2中表示(水平和垂直),并让优化器为特定查询选择最有效的一个
:
是的,一般来说OLTP查询,行格式更好,对于OLAP查询,列存更好。至于存储类型 (或数据模型),我认为DBA特定表格应选择行存储或列存储。至于执行器,根据成本选择优化器是个好主意。这是一个长期的目标,我们的扩展现在需要返回到原始执行器Insert、update、indexScan。我们希望我们的扩张能逐步增强。
2)列存和向量化执行器select sum(x) from T where...查询最有效。不幸的是,这种简单的查询在现实生活中很少使用。通常包括分析查询group by和joint。而且这里的向量模型并不总是最好的(你必须从列中重建join和分组)。为了提高查询执行效率,可能需要为同一数据创建多个不同的投影(按属性的不同子集排序)。
这就是为什么Vertica支持投影的原因VOPS也可以这样做:使用:create_projection什么属性应该是标量,什么可以按时量化。在这种情况下,可以使用标准PG执行器执行分组和join,过滤和持续聚集同时进行向量化操作。
这就是为什么Q1在VOPS快20倍,而不是原型的2倍。因此,我认为列存应该能够维护表中的多个投影,优化器应该能够自动选择其中一个进行特定的查询。投影的同步必须是一个挑战,幸运的是,OLAP最新数据通常不需要。
:
Vertica我测试过中投影,VOPS确实很快。如果你能做出贡献PG内核,太好了。我们的扩张旨在不改变任何事情PG核心代码,用户SQL和现有表。我们将继续优化我们的向量化实现:向量化hashagg要实现向量化hash表、批量计算hash key、批量探测hash表等。当然PG中的原始hash表不是向量化的hash表。
3)我想知道向量化执行器是否只支持内置类型和预定义的操作符?或者它应该能够与任何用户定义的类型、操作符和聚合一起使用?当然,支持内置标量类型要容易得多,但这与PG开放性与可扩展性相矛盾。
:
是的,我们应该支持用户定义的类型。这可以通过引入向量寄存器层映射行类型来完成。int4->vint4
4)你有没有想过?VectorTupleTableSlot存储数据的格式?应该是基准数组吗?或者我们需要以更底层的格式表示向量(例如rel4类型的float数组)
答复:
我们的测试结果显示dataum转换不高效,我们准备使用你提到的底层数组格式来实现datum数组。
https://postgrespro.com/list/id/CAB0yrem3PYu2qQD4=JOg8y_5QAK Q K5yEptxs0t71j5cRyoOQ@mail.gmail.com