存储的未来

对于某些用例,当前存储设计是次优的。我们相信可以通过在”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提供可拔插存储引擎,请参考其手册。

存储引擎

描述

我们在PG中需要这样类似的东西吗?

InnoDB

提供索引组织表,行的老版本在undo表空间。二级索引是间接的,具有单独版本

是的。索引组织表、undo表空间、二级索引是有用的特性。看来,至少其中一些可以使用可拔插存储API来实现

MyISAM

没有事务和恢复的表引擎

不用。如果需要,我们有unlogged表

CSV

Federated

Cassandra

CONNECT

SphinxSE

这些表引擎要么访问本地数据,要么访问外部数据源

不需要。我们有FDWs

MGR_MyIsam

Merge

这些引擎允许定义作为主表集联合的表。这种联合是可更新的:更新被推送到主表。

不需要。我们有可更新视图、分区、表继承等

Archive

归档数据的存储:追加、可压缩存储

是的。归档存储非常有用

Blackhole

静默“吃掉”所有插入数据的表引擎。它在代理中有有用的用例,通过在主端过滤复制流量来减少部分复制中的网络流量。

不需要。我们的逻辑解码已经具备这样能力。此外,还具有相同功能的Blackhole FDW

Mroonga

Mroonga 使用 FTS、地理空间和其他索引实现非事务性表。

不。PG中新的索引类型可以通过索引访问方法来实现

OQGraph

允许查询和对图进行索引的表引擎 。允许用户查询某种视图,而注意数据存储在另一个表中

不。这个表引擎不打算存储主要数据。如果我们需要类似的解决方案,我们应该使用索引访问方法、视图、物化视图来实现它

Sequence

提供generate_series()函数的类似功能

不用。generate_series()完全可以满足这个目的

Aria

XtraDB

MariaDB的MyISAM和InnoDB增强版本

不用。我们应该尽可能避免碎片化

TokuDB

RocksDB

这些引擎提供写优化表。TokuDB 实现了fractal树,而RocksDB实现了LSM树。

是的。写优化表很不错。

ScaleDB

Spider

提供内置在表引擎中的集群

不用。可拔插存储似乎不适合集群的机制

Memory

内存表引擎实现了完全驻留在内存中的非持久表。除了 MySQL 实现的缺点之外,内存引擎可以给我们带来以下好处:更快的内存操作绕过缓冲区管理器;优化磁盘IO相关操作

是的。如果内存表执行的更快,那就太好了。有人可能会反对PG不应该使用内存存储,但若这种存储引擎能够带来显著性能优势,用户就会对它感兴趣

MongoDB

mongoDB也提供可拔插存储,参考其手册。