【问题标题】:How to sort horizontal partitioned data如何对水平分区数据进行排序
【发布时间】:2016-06-30 08:56:25
【问题描述】:

我有一个电信计费软件系统。其中有用户通话的每日日志。日志按日期(月)水平分区。每个分区都存储在一个单独的数据库中,并且可能分布在多个实例中。

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

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

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

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

【问题讨论】:

  • 您只能加载要排序的列和记录id,然后根据排序后的id排序,最后加载要显示的记录。我不确定您是否可以在数据库级别上进行任何有意义的交错,因此在您的代码中进行似乎是最简单的方法。另一种选择可能是将(部分)记录写入内存映射文件并在那里排序,但这可能会花费更多的性能 - 毕竟这里有经典的速度与内存情况。
  • 我们讨论了第一种方法,但是这种方法的缺点是我们需要再次使用Id进行查询,并且由于它来自UI,因此还需要实现分页。
  • 我们遇到过类似的情况,加载所有数据只是占用了太多内存,因此我们采用了首先仅加载要排序的数据和 ids 的方法,然后排序并仅保留身份证。然后分页将对排序后的 id 进行操作,并且只有与页面 id 对应的记录才会被完全加载。当然,您需要再次查询,但是通过分页,您无论如何都必须这样做。为了加快您的第二次(分页)查询,您也可以存储源分区并仅查询这些分区。
  • 他说的是“日志”!他说“排序”!有人会说“hadoop”吗?
  • 我认为@MK。给了一个很好的提示。将与查询/排序标准相关的数据与 id 一起存储在外部缓存、数据网格、NoSQL 数据库或类似的东西中,然后从那里查询 id。或者,您可以使用存储过程来避免加载大量数据,但这可能会对数据库产生性能影响。第三种选择是直接在数据库中维护冗余,而不是在外部存储中。

标签: java sorting database-partitioning


【解决方案1】:

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

详细解决方案:

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

其次,我们在 DAO 上编写了一个 AggregateResultSet 包装器,它包装了来自不同分区的 ResultSet。注意:这些单独的 ResultSets 已经按照相同的标准进行了排序。然后 AggregateResultSet 将被赋予一个动态比较器。

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

我们希望没有比较问题,因为我们在排序中主要是数字/字符串数据。

【讨论】:

  • 听起来是一个有趣的解决方案,它可以减少 Java 应用程序的内存开销。我不确定对数据库的影响,因为理论上你必须保持连接打开以及将结果保存在数据库的缓存中,以便快速检索下一个元素。此外,如果数据库保存在其缓存中的数据被更新,您可能会遇到事务问题。
  • @Thomas,由于是计费系统,数据(通话记录)在各个级别对账后仅上传一次(第+2天),并且永远不会更新(安全)。
  • 如果我正确理解了您的解决方案,分页将非常低效,因为您需要在页面n 之前阅读所有n-1 页面。
  • @draganbozanovic,我们有一个现有的分页实现,我正在尝试理解它。但截至目前,它需要输入结果集和少量参数。
猜你喜欢
  • 2014-09-23
  • 1970-01-01
  • 2022-08-20
  • 2017-03-19
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
相关资源
最近更新 更多