存储的未来
对于某些用例,当前存储设计是次优的。我们相信可以通过在”heap”操作和存储之间添加一个抽象层来进行改进。当前,存储设计基于按行组织页的假设:heapam.h假设:每个tuple只有一个元组头和一个数据区域,即包括HeapTuple及tuple逻辑操作的代码,比如delete、update、加锁。类似,执行器代码表示TupleTableSlot抽象层的元组,该抽象层下面是HeapTuple。2015年2ndQuadrant致力于在PG中实施列式存储项目,以下是根据实施过程中吸取的经验得出的计划。
项目大纲
1) 垂直分区
2) 执行器批处理
3) 执行器向量化
4) 列索引
5) 表的可拔插存储
6) 列式存储插件
当将向量化执行引擎集成到列式存储中时,才能获得最高性能。列式存储不用向量化当然也可以,但是获得的收益却不是最大。因此CPU仍然是一次仅操作一个元素。也可以不在列式存储上做向量化,但收益也很小,因为要使向量化,必须将基于行的数据转换成基于列的数据,这是一个缓慢的操作。
垂直分区
将表的存储区域拆分为多个部分的能力,将列的子集放入每个存储区域。这有几点:
1) 跳过读取查询中不使用的列存储区域
2) 不同列使用不同存储策略(基于行或基于列;基于列的不同实现:实验、压缩或非压缩等)
3) 在具有多个存储区域的元组上读取元组,用于他们之间的join
挑战:
1) 表和存储区域之间进行join需要单独处理
2) Join消除是关键
3) 逻辑/物理元组表示需要改变(尤其是单个atrrelid值的pg_attribute不再表示一个表的元组描述符)
批量执行
指执行器在单个节点一次处理多个元组的能力,而不是当前一次仅处理一个。需要大改TupleTableSlot结构以及节点执行流程。这适用于9.7.
向量化执行
执行器在CPU级别使用SIMD指令用于函数操作的能力。这基于执行器批量执行。聚合操作需要提供专用代码。
列式索引
这个项目关于列存储的新索引访问方法。一个明显的输出是深入了解哪种列存储方法最有效。好处:索引比标准索引更加紧凑,因此扫描速度更快。
表的可拔插存储
这个项目关于为表存储创建一个类似访问方法的接口。目前,所有存储器都通过heapam.c。这使编写不同实现成为可能。PG12开始已支持表访问方法的可拔插。Heapam.c接口假定用于有一个表和一个TID。目前TID只是关系中元组的物理位置。该项目可能需要更高元组标识符以适应不同的存储实现。同时,当前heapam.c实现返回一个包含元组的HeapTuple结构,但不同的实现可能有完全不同的方式来表示存储中的元组。因为我们希望利用元组的不同表示而不是heapify他们。所以可能需要进行更多修改,以便可以将元组传递给执行程序代码。这如何工作,还不清楚,需要更多研究。执行器批处理可以依靠他一次对多个元组进行操作。
Tom Lane的警示
我们需要避免DDL代码的重写。目前所有utility代码都假设HeapTuples可传递到任何地方。对于不同存储格式,这种假设就会失效。我们需要一些方法来避免这个项目陷入无休止的utility代码重构中。
解决方案似乎很简单:不需要在system catalog中立即解决这个问题,如果我们禁止对system catalog使用不同存储格式,我们就不需要边界大量utility代码。
将来有人可以重构涉及单个catalog的代码,以允许将可拔插(非堆)存储用于该catalog。这可以零碎地完成,取消对一个特定catalog的限定。
列存的插件
面向列存储的可拔插存储引擎。
现有用例分析
上面介绍的是PostgreSQL的,分析其他数据库也很有用。
MySQL/MariaDB
MySQL和MariaDB提供可拔插存储引擎,请参考其手册。
MongoDB
mongoDB也提供可拔插存储,参考其手册。