Java 如何对水平分区数据进行排序

Java 如何对水平分区数据进行排序,java,sorting,database-partitioning,Java,Sorting,Database Partitioning,我有一个电信计费软件系统。里面有用户通话的每日记录。日志按日期(月)进行水平分区。每个分区存储在单独的数据库中,可以分布在多个实例上 在UI中,用户将指定日期范围。返回的数据可以在任何字段上排序。日期范围可能跨越多个分区。应用程序必须支持对日期范围的数据进行分页 我无法将太多的记录加载到内存中进行排序。将sort放在查询中只会在一个结果集中提供排序数据 所以我需要对来自多个分区的数据进行排序,每个分区都是单独排序的。如何将已排序的记录从多个已排序的结果集中返回到UI 编辑:在对这个问题进行更多分

我有一个电信计费软件系统。里面有用户通话的每日记录。日志按日期(月)进行水平分区。每个分区存储在单独的数据库中,可以分布在多个实例上

在UI中,用户将指定日期范围。返回的数据可以在任何字段上排序。日期范围可能跨越多个分区。应用程序必须支持对日期范围的数据进行分页

我无法将太多的记录加载到内存中进行排序。将sort放在查询中只会在一个结果集中提供排序数据

所以我需要对来自多个分区的数据进行排序,每个分区都是单独排序的。如何将已排序的记录从多个已排序的结果集中返回到UI


编辑:在对这个问题进行更多分析之后,我们有了更多的投入。还有分页的要求。因此,我们需要找到另一种方法来对多个结果集进行实时排序。

依靠结果集在内存中加载有限数据的能力,我们能够使用动态比较器在Java中找到解决方案。解决方案是从每个resultSet中获取第一条记录,并用java对其进行排序,然后从排序后的数据中返回第一个元素

详细解决方案:

首先,我们建立了一个程序,可以根据屏幕上选择的标准为我们提供一个动态比较器

其次,我们在DAO上编写了一个AggregateResultSet包装器,它包装来自不同分区的结果集。注意:这些单独的结果集已使用相同的条件进行排序。然后AggregateResultSet将获得一个动态比较器

此AggregateResultSet将具有一个数据结构,用于最初存储每个结果集的第一个元素。它将在调用next()时返回下一个元素。根据dynamicComparator,此元素将是最先出现的元素。在next()调用期间,我们从临时数据结构中删除此元素,并从临时数据结构中的相同结果集中插入下一个元素。通过这种方式,AggregateResultSet将以预期顺序返回数据,方法是在Java中合并/存储/排序非常有限的数据


我们希望不会收到任何比较问题,因为我们的排序中大多是数字/字符串数据。

您只能加载要排序的列和记录ID,然后根据排序的ID排序并最终加载要显示的记录。我不确定您是否可以在db级别上执行任何有意义的交错,因此在代码中执行它似乎是最简单的方法。另一种选择可能是将(部分)记录写入内存映射文件并在其中进行排序,但这可能会带来更高的性能成本-毕竟这里有一个典型的速度与内存对比的情况。我们讨论了第一种方法,但这种方法的缺点是我们需要使用Id再次查询,因为它来自UI,分页也需要实现。我们有一个类似的情况,加载所有数据只会占用太多内存,因此我们遵循的方法是首先只加载要排序的数据和ID,然后只排序和保留ID。然后,分页将对排序的ID进行操作,并且只有与页面ID相对应的记录才会被完全加载。当然,您需要再次查询,但是使用分页,您无论如何都必须这样做。为了加快第二次(分页)查询的速度,您还可以存储源分区,并且只查询那些分区!他说“排序”!有人会说“hadoop”吗?我认为@MK.给出了一个很好的提示。将与查询/排序条件相关的数据与ID一起存储在外部的一些缓存、数据网格、NoSQL数据库或类似的地方,然后从那里查询ID。或者,您可以使用存储过程来避免加载大量数据,但这可能会对数据库造成性能影响。第三种选择是直接在数据库中维护冗余,而不是在外部存储器中。这听起来是一个有趣的解决方案,它可以减少Java应用程序中的内存开销。不过,我不确定这对数据库的影响,因为理论上,为了快速检索下一个元素,您必须保持连接处于打开状态,并将结果保存在数据库缓存中。此外,如果数据库缓存中保存的数据被更新,您可能会遇到事务性问题。@Thomas,由于它是计费系统,数据(通话记录)在不同级别的数据协调后只上载一次(第+2天),而且从未更新(安全)。如果我正确理解您的解决方案,分页将非常低效,由于您需要在页面
n
@draganbozanovic之前阅读所有
n-1
页面,因此我们有一个现有的分页实现,我正在尝试理解它。但到目前为止,它需要输入resultset和很少的参数。