Hibernate比sql查询慢1000倍

我有这个设置

@Table(name ="A") EntityA { Long ID; List 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 (ie 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 list = (List)sqlQuery.list(); 

这将是快速的

 String sql = some native sql where parameter = 'actualValue' SQLQuery sqlQuery = session.createSQLQuery(sql); List list = (List)sqlQuery.list(); 

似乎由于某些原因让Hibernate处理参数,它最终会被卡在resultSet中。 这可能是因为数据库的基础查询花费了更长的时间进行参数化。 我最终编写了相当于Hibernate Criteria和Restrictions代码的代码,它直接如上所述设置参数。