【IT168 专稿】传统的关系型数据库管理系统通常只支持行存储表,即数据按记录存储,每条记录的所有属性存储在一起。随着OLAP、数据仓库等查询密集型应用越来越广泛,行存储在应对这类型应用时的局限性逐渐突出,许多厂商适时推出了自己的列存储数据库系统。列存储按表的数据列来组织和存储数据,表的每一个列的数据被存储在一起。DM7实现了列式存储,并支持对用户透明的行、列存储表的混合操作。
(一)DM7列存储表的物理存储
DM7列存储表中的每个列对应两个段。其中一个段用于存储真正的列数据,这些数据被分为若干个区,每个区对应一个区描述项,区描述项存储在另一个段中,用于管理区中的数据,如图1所示。区描述项包含了这个区中所有数据的最大值及最小值,用于在查询时判断这个区是否需要进行扫描,不需就可跳过,从而节省扫描时间;描述项中还包括区数据的存储位置,用于定位数据。
▲图1 列存储表存储架构
(二)DM7列存储表的优势
DM7列存储表主要有以下三方面的优势:
1)吞吐量:访问传统的行存储数据库时,无论感兴趣的是表中的哪些列,都需要先读出完整的每一条记录,这可能意味着读300个字节的数据仅仅检索其中20个字符。而对于DM7的列存储表,可以只读出需要检索的列的数据。由于大部分的OLAP和数据仓库应用中的单个查询往往只涉及表的小部分列,当面对海量数据时,吞吐量的提升是非常巨大的。
2)高效压缩:列存储在压缩方面比传统的行存储数据库更加有效。由于同一列中的所有数据具有相同的数据类型,连续存储的数据具有很大的相似性,数据压缩效率比不同数据类型字段连续存储的行存储表更高。而DM7为不同的数据类型提供了自适应的压缩算法,进一步提高了列存储数据的压缩比。
3)范围索引:由于DM7列存储表的每个区描述项中都存储了区数据的最大值和最小值,且每个列的数据是在段中连续存储的,相当于对每个列都有分段的范围索引,能大大提高数据检索的效率。
(三)DM7行列融合
数据库的执行计划通常以树型的数据结构表示,树中的节点被称为操作符,每个操作符完成一个特定的功能。树的叶节点用于进行数据扫描,从物理存储位置抽取记录,然后向上返回给上层节点。上层节点对记录进行加工,继续向上返回,或者再次向下要求新的记录。
下面举一个简单的例子来说明DM7的行列存储融合。
在DM6中,上述语句会得到图2所示的执行计划。
▲图2 简单连接语句执行计划
图2中CSCN的工作是从一个指定的表中扫描指定的数据,CROSS表示将扫描到的数据进行连接操作,顶层的NSET表示将结果集输出。在执行过程中,CSCN每次从表中只扫描一条记录向上传,上层处理完后再扫描下一条记录,直到两个表都扫描完为止。可以看出以一次一行数据的传递方式为基础的系统构架限制了DM6中使用列存储表的可能性,即使支持列存储表,在传递数据时也要先逐条将其组织成行存储的格式,无法发挥列存储优势,甚至会降低执行的效率。
DM7调整了系统构架,将数据的传输由一次一条数据修改为一次一批数据。引入一个新的数据结构BDTA,这是一个内存数据集合,它是在运行时不同执行节点之间传递数据的核心对象。
BDTA按列的方式组织数据,每个列内各行数据以数组的方式存放,形成一个类似二维数组的数据集合。在执行时,操作符以BDTA为基础进行处理,每一个底层执行节点取到数据之后,都要先将一定数据量的数据(大小可以配置)填到BDTA中,然后再向上传,上层节点得到的是两个BDTA。在DM7中,例子查询语句的执行计划就变为图3所示。
▲图3 简单连接语句执行计划
上图的计划用文本计划表示如下:
#PRJT2: [271, 2880404, 0]; exp_num(2), is_atom(FALSE)
#HASH2 INNER JOIN: [271, 2880404, 0] LKEY_UNIQUE KEY_NUM(1);
#CSCN2: [15, 73049, 0]; INDEX33555442(ORDERS)
#CSCN2: [56, 2880404, 0]; INDEX33555484(CUSTOMER)
BDTA在DM7中相当于一个适配器。一方面,每一个操作符都可以统一对它进行访问和处理;另一方面,无论行存储表或是列存储表都可以将表数据填到对应的BDTA中,区别只在于表扫描操作符的不同,而对于执行计划的上层操作符来说表的存储方式是透明的。
如果把例子查询语句中的表ORDERS修改为列存储表,则其物理查询计划变为如下内容:
#PRJT2: [271, 2880404, 0]; exp_num(2), is_atom(FALSE)
#HASH2 INNER JOIN: [271, 2880404, 0] LKEY_UNIQUE KEY_NUM(1);
#VSCN2: [15, 73049, 0]; INDEX33555442(ORDERS)
#CSCN2: [56, 2880404, 0]; INDEX33555484(CUSTOMER)
可以看出,对ORDERS的扫描操作符变为了VSCN2,填写BDTA的动作由这个操作符完成,填完后将它传给上层操作符HASH2 INNER JOIN处理,对上层操作符来说VSCN2和CSCN2传上来的BDTA是没有任何区别的。
(四)小结
DM7实现了真正的列式存储,并通过对执行计划操作符的改造实现了数据的批量传递和处理,使得可以通过BDTA结构实现对用户透明的行、列存储融合。当查询只涉及表的某几个字段时,使用列存储表可以大大减少填充BDTA的IO,在海量OLAP或数据仓库应用中其优势是显而易见的。