【问题标题】:Get total rowcount before paginating in JOOQ?在 JOOQ 中分页之前获取总行数?
【发布时间】:2023-03-18 00:55:01
【问题描述】:

我很想知道在使用OFFSETLIMIT 分页之前是否有更优化的方法从 JOOQ 查询中获取总行数

我们尝试使用 JOOQs 合成 SEEK 子句,但是由于我们的 ID 是无序 UUID,它不起作用。

我们当前的实现是执行两次查询,第一次是在我们设置偏移量和限制以获取结果/行数之前。

然后我们在第二个查询中得到结果。

    SelectQuery<Record> select = context.selectQuery();
    select.addSelect(FOO_TABLE.fields());
    select.addFrom(FOO_TABLE);


    int totalElements = select.fetch().size();

    select.addOffset(20);
    select.addLimit(50));

    List<Foo> paginatedFoo = select.fetchInto(Foo.class);

这仅仅是这个实现/设计必须接受的东西,还是有任何 JDBC 驱动程序可以消除在 DB 上执行两个查询的需要?

欢迎任何意见或建议!

【问题讨论】:

    标签: java jdbc jooq


    【解决方案1】:

    我们尝试使用 JOOQs 合成 SEEK 子句,但是因为我们的 ID 是无序的 UUID,所以它不起作用。

    当您进行分页时,您按照对用户有意义的内容进行排序。因此,您可能首先要订购/查找其他一些列(例如一些 DATE 列),然后使用 UUID 仅获得明确、稳定的结果。我不明白为什么 SEEK 不适合你。

    如果使用SEEK (keyset pagination) 对您的应用程序有意义,从逻辑上讲,出于性能原因,它是更可取的:

    1. 你不必数,因为没关系
    2. You don't have to use offset

    这只是这个实现/设计必须接受的东西,还是有任何 JDBC 驱动程序可以消除在 DB 上执行两个查询的需要?

    对于数据库来说,这是很多额外的工作。特别是如果你这样做:

    // Don't do this!
    int totalElements = select.fetch().size();
    

    您现在正在传输整个数据集!如果您必须计算单独查询中的行数,至少在数据库中完全运行该查询:

    // Do this instead (prior to adding the limit):
    context.fetchCount(select);
    

    但是为什么不直接使用窗口函数呢?将DSL.count().over() 添加到您的查询中,以计算如果您没有进行分页并且一切就绪,您的查询将产生的总行数。

    之所以可以为此使用窗口函数,是因为它们在所有其他操作(WHEREGROUP BYHAVING 等)之后,但在分页之前(OFFSET、@ 987654335@)。 See this article about the logical order of operations.

    【讨论】:

    • 尤其是在 MySQL 中;在处理大中型数据集时,窗口函数和横向连接的性能非常差。我所做的是获取我的数据,然后执行 foo = count().toInt() 而这基本上是另一个执行 selectCount() 的查询
    • @D.F.:我很好奇窗口计数如何比聚合计数慢。不应该有一个明显的原因,尽管当然可能存在错误。您是否分析了问题并向 MySQL 报告了错误?
    【解决方案2】:

    我在下面给你一个例子,似乎是你正在寻找的。​​p>

            Result<Record> result = dslContext.selectDistinct(
                            REQUEST.ID,
                            count().over().as(TOTAL_ELEMENTS))
                    .from(REQUEST)
                    .groupBy(REQUEST.ID)
                    .orderBy(REQUEST.CREATED_DATE.desc())
                    .offset(pageable.getOffset())
                    .limit(pageable.getPageSize())
                    .fetch();
    

    现在让我们找出总元素。

            int totalElements = 0;
    
            Optional<?> optTotalElements = result.getValues(TOTAL_ELEMENTS).stream().findFirst();
            if(optTotalElements.isPresent()) {
                totalElements = Integer.parseInt(optTotalElements.get().toString());
            }
            double totalPages = (double) totalElements / pageable.getPageSize();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 2017-05-27
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      相关资源
      最近更新 更多