JDBC分页:供应商特定的sql与结果集fetchSize

时间:2015-10-20 16:45:14

标签: java oracle jdbc pagination

互联网上有许多不同的教程,关于JDBC的分页/迭代巨大的结果集。 所以,到目前为止,我发现了很多方法:

  1. Vendor specific sql
  2. 可滚动结果集(?)
  3. 将普通结果集保存在内存中,并仅在必要时映射行(使用fetchSize)
      

    结果集提取大小,可以显式设置,也可以默认设置为相等   对于传递给它的语句提取大小,确定   在随后的任何旅行中检索到的行数   该结果集的数据库。这包括任何仍然的旅行   需要完成原始查询,以及任何重新获取   数据到结果集中。可以明确地或者重新获取数据   隐式地,更新滚动敏感或   滚动不敏感/可更新的结果集。

  4. 光标(?)
  5. Custom seek method paging implemented by jooq
  6. 很抱歉弄乱了所有这些,但我需要有人为我解决这个问题。 我有一个简单的任务,服务使用者通过pageNumber和pageSize请求结果。看起来我有两个选择:

    1. 使用供应商特定的sql
    2. 将连接/语句/结果集保存在内存中并依赖于jdbc fetchSize
    3. 在后一种情况下,我使用rxJava-jdbc,如果你看producer implementation它保存结果集,那么你所做的就是调用request(long n)并处理另外n行。当然一切都隐藏在rxJava的Observable suggar中。我不喜欢这种方法的方法是你必须在不同的服务调用之间保存resultSet,并且如果客户端忘记耗尽或关闭它,则必须清除resultSet。 (注意:这里的resultSet是java ResultSet类,而不是实际数据)

      那么,建议的分页方式是什么?与持有连接相比,供应商特定的sql被认为是慢吗?

      我正在使用oracle,建议不要将ScrollableResultSet用于大型结果集,因为它会在客户端缓存整个结果集数据。 proof

3 个答案:

答案 0 :(得分:1)

无限期地保持资源开放通常是一件坏事。例如,数据库将为您创建一个游标以获取所获取的行。在关闭结果集之前,光标和其他资源将保持打开状态。并行执行的查询越多,占用的资源就越多,并且在某些时候,由于资源池耗尽,数据库将拒绝进一步的请求(例如,一次可以打开有限数量的游标)。 p> 例如,

Hibernate使用供应商特定的SQL来获取“页面”,我会这样做。

答案 1 :(得分:1)

有许多方法,因为有许多不同的用例。

您真的希望用户获取结果集的每一页吗?或者,如果他们感兴趣的数据不存在,他们是否更有可能获取第一页或第二页并尝试其他内容。例如,如果您是Google,那么您可以非常确信人们会查看第一页的结果,少数人会查看第二页的结果,而一小部分结果将来自第三页。在这种情况下,使用特定于供应商的代码来请求数据页面并且仅在用户请求时为下一页面运行该数据,这是完全合理的。如果您希望用户获取结果的最后一页,另一方面,为每个页面运行单独的查询将比运行单个查询和执行多次提取更加昂贵。

用户需要多长时间才能打开查询?有多少并发用户?如果您正在构建一个内部应用程序,数十个用户可以访问,并且您希望用户将游标保持打开状态几分钟,那么这可能是合理的。如果您正在尝试构建一个具有数千个用户的应用程序,这些用户将在几个小时内对结果进行分页,那么保持分配资源是一个坏主意。如果您的用户确实是要获取数据并尽快在循环中处理数据的计算机,那么具有多个提取的单个ResultSet会更有意义。

没有错过任何行/每行只看到一次/跨页的结果是否一致有多重要?单个游标的多次提取可确保结果中的每一行只能看到一次。单独的分页查询可能不会 - 在执行的查询之间添加或删除新数据,您的排序可能不完全确定等等。

答案 2 :(得分:1)

ScrollableResultSet在客户端缓存结果 - 这需要内存资源。但是,例如PostgreSQL默认情况下这样做,没有人抱怨。有些数据库只是使用客户端的内存来保存整个结果集。在大多数情况下,数据库必须处理更多数据才能重新评估查询。 此外,您通常拥有比数据库实例更多的客户端。

另请注意,由Hibernate实现的查询重新执行 - 使用rownum - 并不能保证正确(一致)的结果。如果在执行之间修改数据,则使用默认隔离级别。

这实际上取决于用例。更改Oracle的init参数以获得最大值。连接以及打开游标需要重新启动数据库。 因此,只有在可以预测(并发)用户数量时才能使用ScrollableResultSet和游标。