性能优化技巧 - 遍历

【摘要】
数据分析场景中,充斥着聚合运算,常见的有求和、计数、均值、最大最小值等等,想要获得正确的结果值,遍历技术必不可少,如何更加高效地对数据进行遍历?点击:性能优化技巧 - 遍历,来乾学院一探究竟!java

1. 存储方案

集文件是行存方式,组表有行存和列存两种方式。两种格式都有必定压缩效果。性能优化

首先,咱们来创建一个的普通的文本文件,并在该文件中生成一些数据,代码以下:函数

image.png

代码1.1性能

代码 1.1,生成一个 txt 文件,总记录数为 1000 万,其中部分数据如图 1.1 所示。测试

图1.1fetch

image.png

代码1.2优化

image.png

代码1.3spa

image.png

代码1.4对象

代码 1.二、1.三、1.4 分别使用代码 1.1 创建的 txt 文件,转为集文件 employee.btx、列存组表文件employee.ctx和行存组表文件employee@r.ctx,各文件大小如图 1.2 所示。排序

 

图1.2

按照文件占用的硬盘空间大小排序能够获得:txt> 行存组表 > 集文件 > 列存组表。可见,一样的数据,在不一样的文件存储格式下,所占用的硬盘空间大小也不一样,而文件的大小又会直接影响遍历的效率。

排序能有效提升列存组表压缩效率,重复次数多的字段排到前面。

image.png

代码1.5

代码1.5对原组表文件的level,height,weight,city列依次进行排序。

排序后的组表文件 employee_sort.ctx与原始文件employee.ctx相比,明显变小,如图1.3所示。

图1.3

2. 并行遍历

序表过滤时用 select@m 能够并行计算。

image.png

代码2.1

代码2.1 中:

A二、A5 分别是外存的串行和并行状况,耗时分别为 2742 毫秒和 828 毫秒。

A九、A12 分别是内存的串行和并行状况,耗时分别为 1162 毫秒和 470 毫秒。

集文件和组表上均可以定义多路游标实现并行遍历。列存 + 机械硬盘 + 取用列过多时多路游标不必定会更快。

image.png

代码2.2

代码2.2中:

前 3 行是集文件的并行遍历,耗时 1861 毫秒。

后 5 行是相同数据的列存组表多路游标并行遍历。耗时 2282 毫秒。

使用 fork 语句并行时,不要返回游标。游标只是定义并无实际取数,这种并行没有意义。要在 fork 代码块中作 fetch 或 groups 等实质取数的动做才有意义。

image.png

代码2.3

代码2.3,前6行在fork代码块中完成fetch取数,而后合并结果,查询耗时865毫秒。第7行至12 行,fork 返回游标后,合并再进行 fetch 动做,耗时 1709 毫秒。

3. 过滤条件

多个条件 && 时注意书写次序,若是前面的子项为假时,后面就不会再计算了,这样把容易为假的条件项写到前面,会减小后面条件项的计算次数。

image.png

代码3.1

代码3.1:

A3 中的条件为salary < 10010 && like(name,"*d*"),前面的子项返回结果集较小,查询耗时748 毫秒。

A6 中的条件为like(name,"*d*") && salary < 10010,前面的子项返回结果集较大,查询耗时1814毫秒。

在集合中找成员时(IN 判断),避免在过滤条件中临时计算这个集合。集合成员较多时要先排序,而后用 pos@b 或 contain@b 去判断,将使用二分法。

image.png

代码3.2

在代码3.2中:

A1:取 100 个范围在 1 至 1000000 中的随机数;

A2:为确保后续测试的数据一致,将这 100 个随机数存到文件 keys.txt 中。

image.png

代码3.3

在代码3.3中:

A2:将预先准备的每一个键值都乘以 10。

A5:使用 pos 函数在组表文件 employee.ctx 中找知足 A2 的成员并取出,耗时 15060 毫秒。

image.png

代码3.4

在代码3.4中:

与代码3.3 的区别在于,把代码 3.3 中 A2 的集合搬到了代码 3.4 中 A4 的 cursor 过滤条件中临时计算这个集合,执行耗时 32105 毫秒。相比代码 3.3,虽然结果一致,但耗时多了一倍,应当避免这种写法。

image.png

代码3.5

代码3.5,基于代码3.3,咱们还能够再进行一些优化。

将代码3.3 的 A2 排序,获得了有序键值。

在A5 中的 pos 函数采用选项 @b,使用二分法。执行耗时 7854 毫秒,相比代码 3.3 快了将近一倍。

switch@i@d 可用于快速实现键值过滤,hash 索引经常会比二分法更有效。

image.png

代码3.6

代码3.6 中:

A5:使用switch@i过滤出知足序列A2中的数据,结果与代码3.三、代码 3.四、代码 3.5 一致,耗时为 7104 毫秒。switch函数时会自动建索引@d选项也能够实现过滤效果,这里再也不单独例举。

4. 预先过滤

组表游标在建立时便可写入一些过滤条件。集算器会识别这些条件,利用组表自己的排序信息快速跳到相应的数据位置。另外,这些条件不知足时取出字段就不会被读出,能够减小对象产生次数。而已经产生了游标后再作过滤就没有这些效果了。咱们来看这样一个例子。

image.png

代码4.1

代码 4.1 中:

A3 在组表游标建立时写入过滤条件 level=="one" && height<180 而且只取 city 和 sex 两列数据。

A7 在组表游标建立后,再经过 select 中的过滤条件筛选数据。

随后二者进行了相同的分组聚合运算,结果前者耗时1206 毫秒,后者耗时 4740 毫秒。

5. 游标取数

游标取数性能和每次取出的记录数相关,要作些测试,通常最好是几万行,不要一次只取一行。

image.png

代码5.1

代码 5.1 中:

代码经过遍历组表游标,获取结果,并累计每次结果的记录数。

前6行遍历过程当中每次取10条记录,最终累计耗时7823毫秒。

后6行遍历过程当中每次取50000条记录,最终累计耗时3923毫秒。

还可使用 skip 函数计数,这样没必要把游标数据读出产生成 java 对象。

image.png

代码5.2

代码 5.2 中:

A3 在建立组表游标时取第一列,而后取出该列数据后取得其长度。

A6 对组表游标使用 skip 函数,获取该组表记录数。

这两个单元格计算后的值都为 10000000,但前者耗时 9676 毫秒,后者耗时 6473 毫秒。

6. 遍历复用

使用管道技术能够对基于同一次遍历计算出多个结果,减小硬盘的访问。

image.png

代码6.1

代码 6.1 中:

A二、B二、C2 分别是组表游标 A1 上创建的管道,A三、B三、C3 为这三个管道定义不一样筛选条件并定义取数,A6 中遍历组表游标,每次取 100000 条。A六、B六、C6 返回按前文定义的筛选条件返回的结果集。耗时 5182 毫秒。

第9 行的三个单元格没有使用管道,分别三次创建组表游标再按前文三个相同的筛选条件取出结果。耗时 12901 毫秒。(关于管道的使用,新版本中还有更优写法,代码简洁明了,欢迎各位读者自行体验集算器语法的优雅之处。)" rel="nofollow">性能优化技巧 - 遍历,来乾学院一探究竟!