java – Hibernate比sql查询慢1000倍
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – Hibernate比sql查询慢1000倍,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4563字,纯文字阅读大概需要7分钟。
内容图文
![java – Hibernate比sql查询慢1000倍](/upload/InfoBanner/zyjiaocheng/904/2bf7b213bced4335a9a6adba50a5414a.jpg)
我有这个设置
@Table(name ="A")
EntityA {
Long ID;
List<EntityB> children;
}
@Table(name ="B")
EntityB {
Long ID;
EntityA parent;
EntityC grandchild;
}
@Table(name ="C")
EntityC {
Long ID;
}
SQL查询是这样的(我省略了不相关的细节):
select top 300 from A where ... and ID in (select parent from B where ... and grandchild in (select ID from C where ...)) order by ...
直接数据库中的sql查询或通过Hibernate(3.5)SQL运行比使用Criteria或HQL表达快1000倍.
生成的SQL与HQL和Criteria以及我在那里发布的SQL完全相同.
[编辑]:更正 – sql不完全相同.我没有在管理工作室方面尝试Hibernate样式参数设置,因为直到后来我才意识到这一点 – 请参阅我的回答.
如果我将子查询分成单独的查询,那么它再次快速.
我试过了
>删除子,父,等等的所有映射,并使用Long Id引用 – 同样的事情,所以它不是一个吸引人的,懒惰的,渴望相关的.
>使用连接而不是子查询,并获取与获取和加载的所有组合相同的慢速行为.
>在ID上设置投影而不是检索实体,因此没有对象转换 – 仍然很慢
我查看了Hibernate代码,它正在做一些惊人的事情.它有一个循环遍历所有300个结果,最终命中数据库.
private List doQuery(
final SessionImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws SQLException, HibernateException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = hasMaxRows( selection ) ?
selection.getMaxRows().intValue() :
Integer.MAX_VALUE;
final int entitySpan = getEntityPersisters().length;
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
// would be great to move all this below here into another method that could also be used
// from the new scrolling stuff.
//
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
// that I could do the control breaking at the means to know when to stop
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final List results = new ArrayList();
try {
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
if ( log.isTraceEnabled() ) log.trace( "processing result set" );
int count;
for ( count = 0; count < maxRows && rs.next(); count++ ) {
if ( log.isTraceEnabled() ) log.debug("result set row: " + count);
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies
);
results.add( result );
if ( createSubselects ) {
subselectResultKeys.add(keys);
keys = new EntityKey[entitySpan]; //can't reuse in this case
}
}
if ( log.isTraceEnabled() ) {
log.trace( "done processing result set (" + count + " rows)" );
}
}
finally {
session.getBatcher().closeQueryStatement( st, rs );
}
initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );
if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
return results; //getResultList(results);
}
在这段代码中
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
它使用完整的SQL命中数据库,但在任何地方都没有收集结果.
然后它继续经历这个循环
for ( count = 0; count < maxRows && rs.next(); count++ ) {
对于预期的300个结果中的每一个,它最终会访问数据库以获得实际结果.
这看起来很疯狂,因为在1次查询后它应该已经有了所有结果. Hibernate日志不会显示在此期间发出的任何其他SQL.
有人有任何见解吗?我唯一的选择是通过Hibernate转到本机SQL查询.
解决方法:
我终于成功了解了这一点.问题是由Hibernate将参数与涉及子查询的实际SQL查询分开设置引起的.如此原生SQL,如果这样做,性能将会很慢.例如,这将是缓慢的:
String sql = some sql that has named parameter = :value
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter ("value", someValue);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
这将是快速的
String sql = some native sql where parameter = 'actualValue'
SQLQuery sqlQuery = session.createSQLQuery(sql);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
似乎由于某些原因让Hibernate处理参数,它最终会被卡在resultSet中.这可能是因为数据库的基础查询花费了更长的时间进行参数化.我最终编写了相当于Hibernate Criteria和Restrictions代码的代码,它直接如上所述设置参数.
内容总结
以上是互联网集市为您收集整理的java – Hibernate比sql查询慢1000倍全部内容,希望文章能够帮你解决java – Hibernate比sql查询慢1000倍所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。