关于性能优化:性能优化技巧TopN

2次阅读

共计 2158 个字符,预计需要花费 6 分钟才能阅读完成。

TopN 是常见的运算,用 SQL 写进去是这样(以 Oracle 为例):
       select from (select from T order by x desc) where rownum<=N
这个 SQL 的运算逻辑从其语句上看,要先做排序(Order by),而后再取出前 N 条。

咱们晓得,排序是个十分慢的动作,复杂度很高(n*logn),如果波及数据量大到内存放不下,那还须要进行内外存数据交换,性能还会急剧下降。

而事实上,要计算 TopN,咱们能设计出不须要全排序的算法,只有放弃一个大小为 N 的小汇合,对数据集遍历一次,将遍历过的数据的前 N 名保留在这个小汇合中,遍历到新一条数据,如果比以后的第 N 名还大,则插入进去并丢掉当初的第 N 名,如果比以后的第 N 名要小,则不做动作。

这样计算的复杂度要低很多(n*logN,n 是总数据条数),而且个别 N 都不大,能够在内存中放下,无论数据量有多大,都不会波及内外存替换问题。

然而,SQL 无奈形容下面这个计算过程,这时,咱们只能寄希望于数据库引擎是不是能本人优化。应用 SPL 就容易形容下面这个计算过程,从而实现高性能计算。

咱们来测试一下看 Oracle 是不是会做这个优化,即用 Oracle 实现 TopN 后和 SPL 做同样运算相比。因为 SPL 能应用优化算法,如果 Oracle 的计算工夫和 SPL 差不多,则阐明它做了优化,如果差得很远,则可能是做了全排序。

一、数据筹备和环境

用 SPL 脚本生成数据文件,数据共两列,第一列 id 是小于 20 亿的随机整数,第二列 amount 是不大于 1 千万的随机实数。数据记录为 80 亿行,生成的原始文本文件大小为 169G。利用数据库提供的数据导入工具将此文件数据导入到 Oracle 的数据表 topn 中,同时也用此文件数据生成 SPL 组表文件 topn.ctx。

在一台 Intel 服务器上实现测试,2 个 Intel3014 CPU,主频 1.7G,共 12 核,内存 64G。数据库表数据及 SPL 组表文件均存储在同一块 SSD 硬盘上。

咱们刻意将数据量设计得比内存大,这样如果进行排序则会有内外存替换动作,性能降落会十分大,容易被观测到。

二、惯例 TopN

取出 topn 表中 amount 最大的前 100 条。

1.        Oracle 测试

查问用的 SQL 语句是:

select * from (

select  /+ parallel(4) /

  • from topn order by amount desc

) where rownum<=100;

阐明:/+ parallel(4) / 是 Oracle 的并行查问语法,其中 4 是并行数。

2.        SPL 测试

编写 SPL 脚本执行测试:

与 SQL 不同,SPL 把 TopN 看成是一种聚合运算,和 sum/count 这类运算一样,不同的只是 TopN 将返回一个汇合,而 sum/count 返回的是单值。但它们的计算逻辑是一样的,都只须要对原数据集遍历一次,并且不波及全排序。

A4 格中的 groups(;top(100;-amount) 就是对选集做 TopN 聚合运算,计算出前 100 名。

3.        论断与剖析

惯例 TopN 测试工夫见下表:

测试后果(工夫单位:秒)

测试表明,Oracle 比 SPL 还要更快一点,而 SPL 没有做全排序,这阐明 Oracle 在这种状况会主动优化。

Oracle 比 SPL 快也能够了解,因为 Oracle 是用 C ++ 开发的,而目前版本的 SPL 是用 java 开发的。C++ 比 java 计算更快是失常的,而且这次测试读取了全副的两列数据,且数据随机无序,很难压缩,所以组表的列式存储也没有劣势。

三、减少复杂度

对于最根本的 TopN,Oracle 很聪慧,即便写成了子查问也会优化。咱们上面减少问题的难度,改成分组后在每一组中做 TopN。

具体运算设计为:依照 id 字段最初一位数字值进行分组,而后查问出每组中 amount 最大的前 100 条记录。id 是个整数,这样也就只有 10 个分组,分组自身的计算量并不大,不过要对分组数据做 TopN,整体计算复杂度略高了一些。如果没有全排序,总体运算工夫该当比方才的状况多,但还在同一数量级范畴内。

1.        Oracle 测试

查问用的 SQL 语句是:

select * from (

select  /+ parallel(2) /

       mod(id,10) as gid,amount,

        row_number()over (partition by mod(id,10) order by amount desc) rn

from topn

) where rn <= 100;

SQL 无奈间接写出分组后取 TopN 的运算,只能借助窗口函数计算序号,语法中还是有排序(order by)的字样。

2.        SPL 组表测试

编写 SPL 脚本执行测试:

因为 SPL 把 TopN 看成是聚合计算,所以能够很容易放在分组汇总中,和全量聚合的写法简直是一样的。

3.        论断与剖析

测试后果(工夫单位:秒)

减少难度后,Oracle 比之前的简略状况慢了 10 倍还多,而且比 SPL 做同样运算也慢了近 10 倍。这阐明 Oracle 在这种状况下很可能做了排序动作,状况复杂化之后,Oracle 的优化引擎不起作用了。

而 SPL 在这两种状况下的运算工夫差异不到 2 倍,基本上在同一数量级,合乎咱们之前的剖析,算法的劣势失去了充沛的体现。

正文完
 0