Hibernate参数化sql查询慢和活动的oracle会话

Gil*_*rto 9 java oracle performance spring hibernate

通过对Oracle数据库进行hibernate查询,我一直在苦苦挣扎几天.这样的东西用于将记录提供给网格.

SELECT 
    fields
FROM 
    tables and JoinedTables
WHERE
        Field1  >= :value1
    AND Field2 = :value2
    AND Field3 = :value3
Order By MaintTable.Id Desc
Run Code Online (Sandbox Code Playgroud)

在Spring Java + Hibernate 4.2方法中使用这种方法.

SQLQuery query = (SQLQuery) session.createSQLQuery(querySql)
                                .addEntity(CertificateViewEnt.class)
                                .setParameter("value1", firstCertificateRecordDate)
                                .setParameter("value2", certType.toUpperCase())
                                .setParameter("value3", deleted? 1:0);      
Run Code Online (Sandbox Code Playgroud)

每个过滤的字段都被正确编入索引并在Maintable.Id Descendent上创建一个函数索引以提高性能.

起初我以为是会话/连接池没有被正确管理,所以我改为StatelessSession并添加了这个session.close():

query.setCacheable(false)
              .setTimeout(30)
              .setReadOnly(true);
...
...
//Pagination
query.setMaxResults(rows);
query.setFirstResult(HelperMethod(page, rows));

result = (List<CertificateViewEnt>) query.list(); 
session.close();
return result;
Run Code Online (Sandbox Code Playgroud)

它没有解决它.查询运行好几次,但由于某些未知原因,并且使用之前已成功运行的值,挂起,在Oracle中打开会话(status = ACTIVE)并在超时时失败.在任何SQL客户端上针对Oracle运行相同的查询,并且使用所有可能的params组合进行数十次执行,具有极高的性能,大约400ms,一次10个记录.

在这里和那里阅读了一些文章之后,Link1 [ Hibernate + Java的性能降低但是当我使用TOAD时使用相同的本机Oracle查询 Link2:[ 查询挂起oracle 10g]

我怀疑Hibernate使用的QueryPlan很差,并决定使用绑定参数删除所有过滤器并且也没有解决,尽管它有点好一些.在转移到其他页面(如第1页,第2,3,4页,......)后一段时间被绞死

毕竟,我怀疑Hibernate的方法生成的SQL

query.setMaxResults(rows)
query.setFirstResult(SomeHelperMethod(page, rows));
Run Code Online (Sandbox Code Playgroud)

因为在日志中看到它们作为绑定参数传递给Oracle.

       ...
       Order By Certificado.Id Desc ) row_
       where rownum <= ?)
  where rownum_ > ?
Run Code Online (Sandbox Code Playgroud)

我也在跟踪日志中看到了这一点

2015-09-15 14:09:53 TRACE QueryPlanCache:200 - Located native-sql query plan in cache (SELECT /*+ INDEX(
Run Code Online (Sandbox Code Playgroud)

还有这个:

2015-09-15 14:09:53 TRACE BasicBinder:84 - binding parameter [2] as [VARCHAR] - E
2015-09-15 14:09:53 DEBUG Loader:2031 - bindNamedParameters() 0 -> deleted [3]
2015-09-15 14:09:53 TRACE BasicBinder:84 - binding parameter [3] as [INTEGER] - 0
2015-09-15 14:09:53 TRACE Loader:1931 - Bound [7] parameters total
/*
SLOW here !!!  Around 3 secs when query runs in ~0,300 secs via SQL client.
And ACTIVE sessions are left running in Oracle.
*/
2015-09-15 14:09:56 TRACE JdbcCoordinatorImpl:397 - Registering result set [org.apache.commons.dbcp.DelegatingResultSet@f0c620]
2015-09-15 14:09:56 TRACE Loader:943 - Processing result set
Run Code Online (Sandbox Code Playgroud)

最后,我不得不放弃所有Hibernate绑定参数并实现自定义计算分页并编写所有SQL来检索页面行,并正确运行和管理数据库会话.

所以,我的问题是: 什么是hibernate正在破坏阻止查询在数据库运行时运行的场景?绑定参数查询有任何已知问题吗?

当我有绑定参数时,我真的不喜欢编写所有SQL代码并强制对此SQL进行硬解析.

关于环境的一些注意事项:Tomcat和Oracle位于同一主机上.所以网络连接不是问题

Hibernate版本4.2.15最终版

该表在开发数据库中有大约300k recs(生产中为1,5M),并且一次显示10,20,50个rec的页面,按主键描述排序(生成序列)

希望一些Hibernate专家可以帮助我,这样我仍然可以信任大型数据库项目上的Hibernate查询.提前致谢.

小智 2

我不知道这是否是您的问题,但是 Oracle 在解析查询时会查看绑定变量值,然后保存查询计划以供将来执行,因此每次使用新的查询运行时都不必继续解析查询绑定变量集。但每隔一段时间就会重新解析查询。如果在解析期间碰巧传递了一些不寻常的绑定变量值,则会存储和使用错误的计划。这是绑定变量的诅咒。它们减少了解析,但在再次解析查询时可以翻转非典型绑定变量值的计划。提示可以提供帮助。我们使用 SQL 配置文件来锁定具有倾向于更改计划的绑定变量的查询计划。有时,您可以自定义收集优化器统计信息的时间和方式,以便无论传递给绑定变量的值是什么,都可以创建良好的计划。

不管怎样,这是我一直看到的东西,可能是也可能不是你的问题。

鲍比