(我已阅读Hibernate Pagination using HQL中引用的所有问题,但在我的情况下,这些问题都不是可能的解决方案。)
我有一个用HQL编写的非常复杂的查询,它在索引列上有order by
。当使用Hibernate的内置分页工具(setFirstResult
等)时,任何页面都需要几秒钟才能返回第一页返回的位置<100ms。
我们的DBA对解释计划的分析似乎表明DBMS决定完全针对页面上限的所有行运行复杂查询,然后返回指定的范围。
例如,对于Hibernate生成的查询:
SELECT *
FROM (SELECT row_.*, ROWNUM rownum_
FROM (<very complicated queries>) row_
WHERE ROWNUM <= 100000) row2_
WHERE rownum_ > 99990
DBMS将运行row2_
子查询以真正获取100k行并丢弃第一个99990以获得10。
很明显,“非常复杂的查询”太复杂了,无法通过机器进行优化,因此我决定手动编写一个将分页考虑在内的查询。查询能够在100ms内加载任何页面,但需要从子查询中选择(在from
子句中)。不幸的是,HQL不支持这个,所以我被困住了。
那么有没有人知道在HQL中进行分页的任何其他方法或者在from子句限制中解决无子查询的方法?
详细说明:
数据库是Oracle 11g。 Hibernate版本是3.5。
“非常复杂的查询”在主查询中没有连接的单个驱动器表中从选择部件中选择大约10个不同的子查询。 (这是为了解决HQL对无关左联接的限制。)排序只能在驱动表上的列上进行。
我写的查询基本上选择了可以出现在子查询中“页面”中的所有ID(驱动表实体),然后将主查询限制为这些ID:
driverTable.id in
(SELECT x.i
FROM (SELECT z.i, ROWNUM r
FROM (SELECT A.ID i
FROM DrivingTable a
ORDER BY A.ID DESC) z) x
WHERE x.r BETWEEN :page * 100 + 1 AND :page * 100 + 100)
这成功地欺骗了查询优化器在计算复杂的主查询之前应用行号限制。