【问题标题】:JDBC Pagination: vendor specific sql versus result set fetchSizeJDBC 分页:特定于供应商的 sql 与结果集 fetchSize
【发布时间】:2016-01-19 10:37:32
【问题描述】:

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

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

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

  4. 光标 (?)
  5. Custom seek method paging implemented by jooq

很抱歉搞砸了所有这些,但我需要有人帮我解决这个问题。 我有一个简单的任务,服务使用者要求使用 pageNumber 和 pageSize 的结果。看起来我有两个选择:

  1. 使用供应商特定的 sql
  2. 将连接/语句/结果集保存在内存中,依赖jdbc fetchSize

在后一种情况下,我使用rxJava-jdbc,如果您查看producer implementation,它保存了结果集,那么您所做的就是调用 request(long n) 并处理另外的 n 行。当然,一切都隐藏在 rxJava 的 Observable sugar 下。我不喜欢这种方法的是,您必须在不同的服务调用之间保存结果集,并且如果客户端忘记耗尽或关闭它,则必须清除该结果集。 (注意:这里的resultSet是java ResultSet类,不是实际数据)

那么,推荐的分页方式是什么?与保持连接相比,供应商特定的 sql 是否被认为慢?

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

【问题讨论】:

    标签: java oracle jdbc pagination


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢,没有想过游标数量有限。好点。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 将有两个用例: 1. 另一个服务将调用一个应用程序并获取每个请求的所有数据(数百个 - 顺序)(请求产生完全不同的巨大结果集)。 2. 其他客户端应用程序可能只获取 1,2..5 个页面,但它们很可能同时进行(数百个请求,而不是数千个)。回复:最好不要错过该行,但行每 15 分钟更新一次,因此在此期间结果无论如何都会保持一致。
    【解决方案3】:

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

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

    这真的取决于用例。将 Oracle 的 init 参数更改为最大值。连接和打开的游标也需要重新启动数据库。 所以 ScrollableResultSet 和 cursors 只能在可以预测(并发)用户数量的情况下使用。

    【讨论】:

    • 通过 WHERE update_ts
    • 您还必须处理已删除的记录。或者您必须仅使用“逻辑”删除 - 只需将记录标记为已删除。此外,您可能需要查看第一次执行时的记录。一致性问题很复杂,通常不值得尝试。当使用更复杂的联接时,重新执行可能会对性能产生重大影响。通常您可能希望为每个页面更改查询的执行计划。第一页可以比最后一页更容易返回。对于 Oracle 来说,使用单个 exec 来“啜饮”结果要容易得多。计划。
    • 感谢您的宝贵意见。事实上,我错过了删除案例,并且错过了一旦我更新了旧记录,即使我有那个 WHERE 子句,它也会将第二页向下移动一个元素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 2018-02-24
    • 1970-01-01
    相关资源
    最近更新 更多