在 JOOQ 中分页之前获取总行数?

tom*_*ato 3 java jdbc jooq

我很想知道在使用OFFSETLIMIT

我们尝试使用 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);
Run Code Online (Sandbox Code Playgroud)

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

欢迎任何意见或建议!

Luk*_*der 5

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

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

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

  1. 你不必数,因为没关系
  2. 您不必使用偏移量

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

数据库需要做很多额外的工作。特别是如果你这样做:

// Don't do this!
int totalElements = select.fetch().size();
Run Code Online (Sandbox Code Playgroud)

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

// Do this instead (prior to adding the limit):
context.fetchCount(select);
Run Code Online (Sandbox Code Playgroud)

但是为什么不直接使用窗口函数呢?添加DSL.count().over()到您的查询以计算如果您没有分页,您的查询将产生的总行数,并且您已经全部设置好了。

为什么你可以使用窗口功能,这样做的原因是因为他们所有的其它操作(后方便计算WHEREGROUP BYHAVING,等),但前分页(OFFSETLIMIT)。请参阅有关操作的逻辑顺序的这篇文章