如何在HQL中显式执行分页(或在from子句中执行子查询)

时间:2013-11-22 19:45:34

标签: hibernate subquery hql paging

(我已阅读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)

这成功地欺骗了查询优化器在计算复杂的主查询之前应用行号限制。

0 个答案:

没有答案