【性能优化】3.4 [外存查找] 行存和带值索引

 

【性能优化】3.3 [外存查找] 排序索引

3.4 行存和带值索引

上一章讲过,列式存储是提高性能的常用手段。然而,对于大多数查找任务来讲,列存却会导致更差的性能。

即使已经有序存储了,通常的列存也可以认为就无法执行不依赖于索引的二分法,这个道理和前面说的列存分段的困难是一样的,不能保证各列的同步性。使用倍增分段机制的列存可以执行二分法了(组表就是这么做的),但也要到每个字段的数据块分别去读取数据,性能不会很好。

列存数据表上也可以建立索引来避免遍历,但非常麻烦。理论上讲,要在索引中把各个字段的物理位置都记录下来,索引容量就会比行存时的索引大很多,甚至可能和原数据表一样大(因为每个字段都有个物理位置,索引中的数据量和原数据相同,仅是数据类型简单)。而且,读取时也要分别到各个字段的数据区去读,而硬盘有个最小读取单位,这会导致各列的总读取量远远超过行存时候,表现出来就是查找性能差很多。

列存更适合数据的遍历。需要高性能查找的场景,尽量不要使用列式存储。

SPL 因为采用了倍增分段机制之后,可以较迅速地按记录序号在列存格式中找到各字段值,所以 SPL 在索引中事实上保存的并不是各个字段值的物理位置,而是整条记录的序号。这样索引的容量就能小得多,和行存时差不多。但仍然需要到各个字段的数据块分别读取,性能还是赶不上行存上的索引。

SPL 的组表缺省会使用列存,但也提供行存模式,可以在创建时用选项 @r 指明:


A

B

1

=file("data.ctx").create@r(ID,…)

对于遍历和查找都要求很高的场景,就只能用空间换时间了。数据冗余存储两遍,列存用于遍历,行存用于查找。

SPL 还提供了一种带值索引,在建立索引时可以把其它字段值一起复制过来,原组表可以继续采用列存用于遍历,而索引本身已经保存了字段值并使用行存,在查找时一般不再访问原组表,能获得更好的性能,但也会占用更大的存储空间。


A

1

=file("data.ctx").open()

2

=file("data.idx")

3

=A1.index(A2;ID;…)

4

=A1.icursor(…;ID==123456;A2).fetch()

5

=A1.icursor(…;ID>=123456 && ID<=654321;A2)

A2 建立索引时将要引用的字段抄在参数的…部分,就可以在索引中复制这些字段值,以后取出目标值时,只要涉及字段在这部分内,就不必再读取原组表。读者可以自行对比带值索引和普通索引的性能以及空间差异。

【性能优化】3.5 [外存查找] 索引预加载
【性能优化】 前言及目录