简化Hibernate的查询

Rue*_*art 7 java oracle hibernate

我有以下代码从Oracle数据库的单个表中执行简单查询.

entityManager.createQuery(
        "SELECT a FROM " + Person.class.getSimpleName() 
        + " a WHERE lower(a.firstName) = '" + firstName + "'")
        .getSingleResult();
Run Code Online (Sandbox Code Playgroud)

Hibernate生成以下sql:

select
        * 
    from
        ( select
            person0_.id as id75_,
            person0_.FIRSTNAME as FIRSTNAME75_,
            person0_.LASTNAME as LASTNAME75_
        from
            PERSONS person0_ 
        where
            lower(person0_.FIRSTNAME)='john' ) 
    where
        rownum <= ?
Run Code Online (Sandbox Code Playgroud)

我们的DBA建议,出于性能原因,此查询应该更简单.如何使hibernate简化查询,如下所示:

select ID, FIRSTNAME, LASTNAME from PERSONS 
where lower(FIRSTNAEM) = 'john' and rownum <= 1
Run Code Online (Sandbox Code Playgroud)

谢谢

ben*_*y23 8

我刚刚查看了explain plan与您类似的查询,两个查询的计划完全相同,所以我不确定您的DBA建议的性能原因.

通过select * from ( ... ) where rownum = 1引入一个STOPKEY来包装查询,该STOPKEY在一行之后停止内部查询.Oracle知道您实际上并不想从子查询中获取所有结果,而只是获取第一行.

如果不修改hibernate源代码本身,就不可能改变Hibernate生成的查询.

注意,当您尝试引入ORDER BY子句时,这种嵌套是必要的原因变得很明显:

select ID, FIRSTNAME, LASTNAME 
  from PERSONS 
 where lower(FIRSTNAME) = 'john' 
   and rownum <= 1
 order by LASTNAME
Run Code Online (Sandbox Code Playgroud)

产生不同的结果

select * from (
    select ID, FIRSTNAME, LASTNAME 
      from PERSONS 
     where lower(FIRSTNAME) = 'john' 
     order by LASTNAME)
  where rownum <= 1
Run Code Online (Sandbox Code Playgroud)

因为where rownumorder by clause... 之前适用

编辑:

这里是参考解释计划的输出,这两个查询完全相同:

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     1 |   112 |     2   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY     |            |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| TABLE_NAME |     1 |   112 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

通过放置功能索引可以提高性能,lower(FIRST_NAME)但两个查询将使用完全相同的功能.


kos*_*tja -2

简而言之 - 你不知道。几乎没有足够的理由来调整 Hibernate 生成的查询,并且我严重怀疑是否可以在不修改源代码的情况下进行调整。

我能想到的唯一简化是调用getResultList().get(0)而不是getSingleResult(). 它会稍微简化生成的 SQL,但会导致性能下降,而不是改进,因为您将从数据库中获取所有匹配的行。

不过,您可以稍微改进一下查询。

您知道您正在查询的类的简单名称。无需先从实体获取并连接,只需使用

SELECT a FROM Person a...

连接查询参数并不是一个好的做法。它使您的查询容易受到 SQL 注入攻击。最好写成:

...WHERE lower(a.firstName) = :firstName");
query.setParameter("firstName", firstName);
Run Code Online (Sandbox Code Playgroud)