任何人都可以告诉我如何在SQL数据库中实现聚合函数,例如:Oracle或SQL Server。
我的意思是,当select子句中存在聚合函数时,这些数据库是否使用了一些内部数据结构或算法。
我之所以这样问是因为我在java ArrayList中有100,000条记录,当我尝试所有值的总和时,它需要大约1分钟但是当相同的100,000条记录存储在DB中时我会使用sum( column_nm)它几乎在1/4的时间内执行。
我想以类似的方式改进我的java代码性能,我想知道SQL聚合函数的内部结构。
感谢。
答案 0 :(得分:2)
虽然这与内部定义的聚合的工作方式不完全匹配,但在SQL Server中,您可以创建user-defined aggregates。看到这样的聚合必须定义的方法可能是有益的:
Init
:查询处理器使用此方法初始化聚合的计算。对于查询处理器正在聚合的每个组,将调用此方法一次。查询处理器可以选择重用聚合类的相同实例来计算多个组的聚合。 Init方法应该根据此实例的先前使用情况执行任何清理,并使其能够重新启动新的聚合计算。
Accumulate
:...查询处理器使用此方法累积聚合值。对于正在聚合的组中的每个值,将调用一次。查询处理器总是在调用给定的aggregate-class实例上的Init方法之后才调用它。此方法的实现应更新实例的状态,以反映传入的参数值的累积。
Merge
:此方法可用于将此聚合类的另一个实例与当前实例合并。查询处理器使用此方法合并聚合的多个部分计算。
Terminate
:此方法完成聚合计算并返回聚合的结果。 ...
从Merge
和Terminate
的描述中,我们可以推断服务器可能并行执行单个组内的多个部分聚合。一旦发生了这些并行累加中的每一个,所有结果将Merge
d在一起,然后在类的一个实例上对Terminate
的最终调用产生最终的聚合结果。
因此,实现加速(如果可能)的一种显而易见的方法是并行化累积阶段。
答案 1 :(得分:2)
有一个非常简单的解释,为什么java代码要慢得多:
您正在使用ArrayList,因此我假设您将Integer-Objects放在那里。它们在某些堆栈中的C中具有显着的开销。 第二,当你总结它们并为每个部分总和创建另一个Integer时,你的GarbageCollector会吃掉所有的性能。
如其他答案所述,
您可以在代码中解决它:使用int []
int[] parts;
sum=0;
for (int i:parts) {
sum+=i;
}
如果根据处理器数量拆分(映射)数组并将其与Future进行并行化,则可能需要测试,这取决于数据的大小。
答案 2 :(得分:1)
性能差异仅仅是因为计算SUM,您不需要同时将所有数据存储在内存中。
当您向数据库发出直接询问SUM的查询时,它可以从磁盘读取每条记录,在内存中的单个变量中累计运行总计,然后读取下一条记录 - 它永远不需要保留所有记录在记忆中同时。更重要的是,它不需要通过网络将这些记录发送到任何其他服务器进行处理 - 它只需要在最后将结果SUM作为单个数字发送。
另外,因为总体上的SUM等于整体的任何不同子集的SUM,所以SUM可以被并行化 - 例如,如果数据是分区的,那么数据库可以发出多个查询以在不同的会话中运行,每个查询将对其部分数据进行SUM,然后控制会话可以简单地对每个分区的结果进行SUM。
当您使用数组计算Java程序中的总和时,它必须首先向数据库发出查询,询问它所需的所有数据;所有数据都需要从数据库传输到应用服务器,并且需要分配内存来存储所有数据。只有在那之后你的程序才会在内存中迭代数组并计算Sum;然后,它可能需要从内存中释放数组。
如果数据量较低,性能差异可能不大。但是,如果音量很大,那么差异可能会非常显着。
答案 3 :(得分:0)
聚合通常只是迭代结果集,然后执行聚合,无论是总和,平均值还是计数等。
如果你在谈论操作的复杂性,它几乎总是O(n),其中n是结果集中用于简单聚合的记录数。
我不明白为什么在java中需要花费更长的时间,因为你的数组会被实例化到主内存中,这比从磁盘中读取更快,就像RDBMS那样。老实说,来自RDBMS的聚合应该比arraylist聚合稍慢。
为了扩展这一点,如果你想要特定条目的一行(带有PK或索引),对于一个arraylist来说它是O(1)而对于一个具有适当索引的RDBMS来说是O(1)(对于一个标准的链表,获取该行将是o(n),但与聚合的arraylist相同。迭代整个数据集(无论是数组还是表),执行聚合几乎总是O(n)。
答案 4 :(得分:0)
有趣的问题。
精心编写的rdbms是数千名博士数学家和数据库专家的工作时间的高潮。你试图模仿MSSQL或postgressql的性能是令人钦佩的,但是在风车上倾斜(如果你不熟悉堂吉诃德,那就太难看了。)与rdbms的一个常见误解是关系意味着相关的表。相关实际上是指数学关系。基本上 - rdbms专注于集合论。即使有很好的rdbms,开发人员也可以通过逐行计算事物来破坏性能,而不是使用固有的本机集。这实际上是您正在经历的性能差异的恰当比较。
如果您仅限于在java而不是db中执行此计算,则应该考虑优化数据结构(最小数据类型)和循环效率。你仍然无法与sql server或postgres竞争。如果你真的需要改进的性能,可能值得将这些项存储在数据库中并从java中调用它们。