反排序优化
概念
随着页码的不断睁大,分页查询的效率会越来越低。为了解决这个问题,Jimmer支持了反排序优化。
反排序优化必须在一下前提同时满足时才生效:
-
此功能并不针对只关心页内数据而不关心分页前总行数的的查询,即
limit(limit, offset)
。必须是同时关心页内数据和总行数的查询。 -
样板查询必须具备明确的orderBy子句。
-
被查询的那一页的数据在分页前所有数据中偏后。即
offset
+pageSize
/ 2 >totalCount
/ 2
当以上条件都满足时,Jimmer会颠倒样板查询的排序。因为,页码相对较大的正排序查询和页码相对小的反排序查询等价。
例子
让我们来看一个例子。
SpringBoot的Page<E>
类型的定义过于复杂,不利于本文通过打印结果进行演示,所以我们采用Jimmer定义的Page类,而非SpringBoot并采用自定义Page类。
分页查询代码为
- Java
- Kotlin
public Page<Book> findBooks(
int pageIndex,
int pageSize
) {
BookTable table = Tables.BOOK_TABLE;
return sqlClient
.createQuery(table)
.orderBy(table.name().asc(), table.edition().desc())
.select(table)
.fetchPage(pageIndex, pageSize);
}
fun findBooks(
pageIndex: Int,
pageSize: Int
): Page<Book> =
sqlClient
.createQuery(Book::class) {
orderBy(table.name.asc(), table.edition.desc())
select(table)
}
.fetchPage(pageIndex, pageSize)
我们假设Book
记录共12条,如果pageSize
为2,共6页,pageIndex
的有5个取值:0、1、2、3、4、5。
-
0、1、2: 要查询的数据偏前,采用正排序分页
-
3、4、5: 要查询的数据偏后,采用反排序分页
接下来,我们分别以pageIndex=2
和pageIndex=3
为例,展示反排序分页和正排序分页的差异。
正排序
执行findBooks(2, 2)
,生成的正排序SQL为
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
order by
/* highlight-next-line */
tb_1_.NAME asc,
/* highlight-next-line */
tb_1_.EDITION desc
limit ? /* 2 */
offset ? /* 4 */
得到的结果为
{
"rows":[
{
"id":11,
"name":"GraphQL in Action",
"edition":2,
"price":81,
"store":{
"id":2
}
},
{
"id":10,
"name":"GraphQL in Action",
"edition":1,
"price":80,
"store":{
"id":2
}
}
],
"totalCount":12,
"totalPage":6
}
反排序
执行findBooks(3, 2)
,生成的正排序SQL为
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
order by
/* highlight-next-line */
tb_1_.NAME desc, // 反序:asc变desc
/* highlight-next-line */
tb_1_.EDITION asc // 反序:desc变asc
limit ? /* 2 */
offset ? /* 4 */
得到的结果为
{
"rows":[
{
"id":3,
"name":"Learning GraphQL",
"edition":3,
"price":51,
"store":{
"id":1
}
},
{
"id":2,
"name":"Learning GraphQL",
"edition":2,
"price":55,
"store":{
"id":1
}
}
],
"totalCount":12,
"totalPage":6
}