分类: 数据库开发技术
2014-08-08 20:04:24
纵列数据和“序列”数据类型
关系数据库管理系统使用表这个概念对数据进行逻辑存储,表由行和列组成。面向对象的数据库管理系统和诸如eXtremeDB金融版等“对象友好型”数据库系统使用对象的类来代替表,但是从概念上来说,类和表相同,为了简单起见,本白皮书统一使用“表”。
传统(关系和面向对象)的数据库管理系统是面向行的,因此它们基于行对存储的数据进行操作。数据库系统将行组织成数据库页面,数据库页面是数据库管理系统输入/输出的基本单位。当数据库管理系统读取数据时,无论是从数据库的缓存还是持久性介质进行读取,都需要将一个数据库页面转移到CPU的一级/二级缓存中。例如,假设表如下面的图 1所示,数据库页面大小为4096字节,一个页面可以容纳约145行数据。该图相当于两个数据库页面。图中列出的行号仅限于说明的目的。
行号 |
股票代码 |
开盘价 |
收盘价 |
成交量 |
日期 |
1 |
IBM |
204 |
205 |
200000 |
20120410 |
2 |
IBM |
202 |
203 |
150000 |
20120411 |
3 |
IBM |
204 |
205 |
300000 |
20120412 |
… |
… |
… |
… |
… |
… |
145 |
IBM |
206 |
202 |
400000 |
20120927 |
150 |
IBM |
202 |
203 |
200000 |
20120928 |
151 |
IBM |
203 |
202 |
200000 |
20120929 |
152 |
IBM |
202 |
205 |
400000 |
20120930 |
… |
… |
… |
… |
… |
… |
290 |
IBM |
210 |
209 |
150000 |
20130316 |
图 1.
基于行处理的方法存在的问题是,对于时间序列数据的分析(即下文的市场数据分析),特定操作很可能只对这些列的某个子集感兴趣。例如,许多金融计算可能只使用其中一个字段比如收盘价(图 1中的“收盘价”列)。面向行的处理会获取整个页面,并将其装入到CPU缓存中,这就包括了同该操作无关的“股票代码”、“开盘价”、“交易量”和“日期”等字段。换句话说,由于实际使用的数据只是全部获取数据的一部分,因此浪费了大量带宽。计算中使用“收盘价”列,但是却将“股票代码”、“开盘价”、“交易量”和“日期”列都转移到一级/二级缓存中,而这仅仅是因为传统面向行数据库管理系统所采用的数据组织方式。
这造成了同操作无关的数据对缓存的“大量占用”,而这个问题可以通过基于列的数据库来解决,顾名思义,这种方案将数据按列装入到一级/二级缓存中。在上述例子中,如果采用列优先的方法,可以将“收盘价”这列的数据装入到数据库页面中, 直到达到页面大小的限制。在将此页面移入CPU缓存时,与基于行处理的方法相比,每次转移都能够将更多的“收盘价”列数据转移到一级/二级缓存中。转移带宽的使用效率更高,需要的获取次数更少,因此显著缩短了时延。
然而,虽然基于列处理能够加快对数据列的分析处理,但是在其它情况下(例如要求对多列进行操作的“常规”数据处理),基于行管理通常更快。事实上,许多资本市场应用程序管理的数据,既有适合按列处理的数据,也有适合按行处理的数据。
利用eXtremeDB金融版,开发人员可以灵活实施基于列和基于行的数据处理,并且能够在一个表中使用将这两种模式相结合的混合解决方案。它是通过独有的“序列序列”数据类型实现的这一功能。使用eXtremeDB金融版的C/C++开发人员先创建一个文本文件格式的数据库架构(设计),然后使用McObject的mcocomp工具对其进行编译,得到头文件和数据库词典,以便在相应的应用程序中调用。E声明了表不同列的数据类型。例如,下面的架构创建了Security表(类),其中一列为固定长度的字符串类型,五列为可变长度的字符串类型,还有九列被声明为序列序列(sequence)数据类型:
class Security
{
char<16> Id;
string ID;
string Ex;
string Descr;
string SIC;
string Cu;
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
sequence
};
在上面的表中,char和string是标量数据类型,这种数据类型只能容纳一个元素。与此相对,sequence是一种无限数组,可以容纳多个元素。从概念上说,可以将两个或多个sequence类型的数据视为时间序列数据。在上述例子中,可以将四组sequence数据视为四个时间序列数据。某些编程语言支持矢量运算,但通常要求将矢量驻留在内存中,因此限制了它们的实用性。(如果需要运算的矢量非常大和/或可用的系统内存非常小,那么系统可能无法完成该运算,或者会降低系统性能,因为操作系统不得不在物理内存和虚拟内存之间多次数据交换。)此外,对于基于矢量的语言,下面的表达式
result = a * b / c
必须先得到(实例化)运算a * b的中间结果(另一个矢量),才能执行下一个运算(将该矢量除以矢量c)。假设,矢量a和b含有1亿个元素,每个元素是一个4字节的无符号整数(4亿字节),则必须得到第三个包含4亿元素的中间矢量的中间结果(然后将每个元素除以矢量c的元素,得到最终的结果矢量)。毫无疑问,4亿字节的矢量无法装入CPU的缓存中,因此不得不在内存(DRAM)中进行创建,从而需要在CPU和DRAM之间进行大量数据移动,造成了时延。
eXtremeDB金融版采用C语言编写,eXtremeDB用户通常以C或类似语言(C++、Java、C#、Python)进行编程。这些语言都不属于矢量编程语言,但是可以使用C语言实现矢量(数组)处理,而eXtremeDB金融版提供了包括超过150函数的函数库,可用于对sequence数据进行基于矢量的统计分析。
为了克服矢量编程语言要求将整个矢量驻留在内存中的限制。eXtremeDB金融版实施了一个名为区块(tile)的专用数据库页面类型。该页面类型用于将序列数据装入到一级/二级缓存中。McObject使用术语“对矢量元素按区块处理”来描述eXtremeDB金融版对时间序列数据的处理,利用该产品基于矢量的统计函数按序列处理所存储的数据。对于上述包含“开盘价”、“收盘价”、“成交量”和“日期”元素的表来说,可以只将需要处理的“收盘价”数据的区块装入CPU缓存,如图2所示。
英文 |
中文 |
Close |
收盘价 |
图 2.
在eXtremeDB金融版中,sequence类型的字段可以与所有其他支持的数据类型一起在表中使用;该数据库系统“知道”以列优先的方式处理时间序列数据,并且对其他类型的数据基于行处理,如下面的图3所示。
SHAPE \* MERGEFORMAT
英文 |
中文 |
Symbol |
股票代码 |
Exchange |
交易所 |
Open |
开盘价 |
Close |
收盘价 |
Volume/Vol |
交易量 |
Date |
日期 |
Row |
行 |