我在针对Oracle数据库进行hibernate查询时已经挣扎了好几天。 这样的东西用于将记录提供给网格。
SELECT
fields
FROM
tables and JoinedTables
WHERE
Field1 >= :value1
AND Field2 = :value2
AND Field3 = :value3
Order By MaintTable.Id Desc
在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);
每个已过滤的字段都已正确编入索引,并在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;
它没有解决它。 查询运行好几次,但由于某些未知原因,并且使用之前已成功运行的值,挂起,在Oracle中打开会话(status = ACTIVE)并在超时时失败。 在任何SQL客户端上针对Oracle运行相同的查询,并且使用所有可能的params组合进行数十次执行,具有极高的性能,大约400ms,一次10条记录。
在这里和那里看了一些文章后, Link1 [Slow performance on Hibernate + Java but fast when I use TOAD with the same native Oracle query Link2:[query hangs oracle 10g
我怀疑Hibernate使用的QueryPlan很差,并决定使用绑定参数删除所有过滤器,但也没有解决,尽管它有点好一些。在转移到其他页面(如第1页,第2,3,4页,......)之后暂停了一段时间。
毕竟,我怀疑Hibernate的方法生成的SQL
query.setMaxResults(rows)
query.setFirstResult(SomeHelperMethod(page, rows));
因为在日志中看到它们作为绑定参数传递给Oracle。
...
Order By Certificado.Id Desc ) row_
where rownum <= ?)
where rownum_ > ?
我也在Trace Log
中看到了这一点2015-09-15 14:09:53 TRACE QueryPlanCache:200 - Located native-sql query plan in cache (SELECT /*+ INDEX(
和此:
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
最后,我不得不放弃所有Hibernate绑定参数并实现自定义计算分页并编写所有SQL以检索页面行,并且它正在运行并正确管理数据库会话。
所以,我的问题是: 什么是hibernate正在破坏阻止查询在数据库运行时运行的场景? 绑定参数查询有任何已知问题吗?
当我有绑定参数时,我真的不喜欢编写所有SQL代码并强制对此SQL进行硬解析。
关于环境的一些注意事项: Tomcat和Oracle在同一台主机上。所以网络连接不是问题
Hibernate版本4.2.15 final
该表在开发数据库中有大约300k recs(生产中为1,5M),并且一次显示10,20,50个rec的页面,按主键描述(生成序列)排序
希望一些Hibernate专家可以帮助我,这样我仍然可以信任大型数据库项目上的Hibernate查询。 提前谢谢。
答案 0 :(得分:1)
我不知道这是否是您的问题,但Oracle在解析查询时会查看绑定变量值,然后保存查询计划以供将来执行,因此它不必每次都解析查询它使用一组新的绑定变量运行的时间。但每隔一段时间重新解析一次查询。如果在解析期间碰巧传递了一些异常的绑定变量值,则会存储并使用错误的计划。它是绑定变量的诅咒。它们减少了解析,但是当再次解析查询时,可以在非典型绑定变量值上翻转计划。提示可以提供帮助。我们使用SQL配置文件来锁定具有易于更改计划的绑定变量的查询计划。有时您可以自定义何时以及如何收集优化程序统计信息,以便无论将哪些值传递到绑定变量,都可以创建一个好的计划。
无论如何,它是我一直看到的东西,可能是也可能不是你的问题。
巴比