Java 简单的hibernate查询返回速度非常慢

Java 简单的hibernate查询返回速度非常慢,java,hibernate,objectinstantiation,Java,Hibernate,Objectinstantiation,我有以下hibernate查询: Query query = session.createQuery("from MyHibernateClass"); List<MyHibernateClass> result = query.list();// executes in 7000ms 在MyHibernateClass数据库表中3500行的小数据集上测量jvm中的java代码时,大约需要7000ms 另一方面,如果我使用直接jdbc,如下所示: Statement stateme

我有以下hibernate查询:

Query query = session.createQuery("from MyHibernateClass");
List<MyHibernateClass> result = query.list();// executes in 7000ms
在MyHibernateClass数据库表中3500行的小数据集上测量jvm中的java代码时,大约需要7000ms

另一方面,如果我使用直接jdbc,如下所示:

Statement statement = session.connection().createStatement();
ResultSet rs = statement.executeQuery("select * from MyHibernateClass");// 7ms
List<MyHibernateClass> result = convert(rs);// executes in 20ms
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
然后是以下日志语句中的3500条

[2011-07-07 14:26:26,649]DEBUG [main] [logid: ] - 
  org.hibernate.loader.Loader.getRow(Loader.java:1197) - 
  result row: EntityKey[com.mycom.MyHibernateClass#1]
然后是3500个日志语句,如

[2011-07-07 14:27:06,789]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:130) - 
  resolving associations for [com.mycom.MyHibernateClass#1]
[2011-07-07 14:27:06,792]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:226) - 
  done materializing entity [com.mycom.MyHibernateClass#1]
这是什么意思


在第一个实现中,Hibernate在做什么?我怎么知道呢?

如果您在应用程序中使用Log4j,您可以针对Hibernate设置各种不同的日志选项,以便更好地了解Hibernate的幕后情况


我猜这是在应用程序中首次调用HQL查询时发生的典型初始加载时间。在第一次查询之后,后续的HQL查询应该会显著加快。

基于新的信息,我觉得我应该提供另一个答案。不同之处在于,您在bean中为列表或集合属性指定了一对多关联

您可能正在指定将关闭延迟加载的
lazy=false
。在禁用延迟加载的情况下,它将获取每个
MyHibernateClass
实体的所有关联记录,这就是为什么它要花这么长时间执行


尝试设置
lazy=true
,这将执行得更快,然后仅在从实体显式请求关联实体时检索它们。

添加一个具有类的所有属性的构造函数就成功了,现在hibernate查询的执行时间是70毫秒。以前,这个类只有一个没有参数的默认构造函数和一个带有实体id参数的构造函数。

我知道这个线程很旧,但是为了更新,我遇到了同样的问题,但是使用SQL Server,结果是Hibernate打印的SQL和使用驱动程序发送的SQL是不同的。默认情况下,使用MSSQL驱动程序会将查询作为存储过程发送给RPC调用,这是因为驱动程序尝试优化MSSQL标准的查询计划,所以它会发送类似以下内容的查询

休眠查询:

select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
@param1=somevalue, @param2=somevalue 
declar sp ....

  select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
go
实际驱动程序发送查询:

select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
@param1=somevalue, @param2=somevalue 
declar sp ....

  select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
go
注意:这个查询是通过SQL Profiler工具直接在DB上监听得到的

事实证明,MSSQL上的sp_exec优化往往会产生良好的缓存查询计划,但这会导致“参数嗅探”,以便了解更多有关此问题的信息,请阅读此处

因此,为了克服这一问题,我有以下选择:

  • 将我的HQL更改为本机查询,并为某些参数添加选项“重新编译”

  • 使用直接查询值而不是准备好的语句,这样就不会转换参数值,并且驱动程序不会将查询修改为存储过程

  • 将驱动程序设置更改为不发送存储过程(这仍然不好,因为现在MSSQL server中的查询计划将特定于此查询,这与选项2相同,但不在代码范围内)

  • 我不想使用选项1和2,因为这消除了使用ORM框架的全部目的,现在我使用选项3

    因此,我将JDBCURL更改为发送选项prepareStatement=false

    设置此选项后,我又遇到了一个问题,查询发送时如下所示

     Select * from customer c where c.name like **N**'somename' and c.country=**N**'somevalue'
    
    这里的值前面有一个前缀,表示要转换编码方案,所以我禁用JDBCURL,使其为sendUnicode=false

    这就是我在JTDS驱动程序选项中所做的一切。。就我而言,现在应用程序已经启动并运行得很快了。我还引入了二级缓存来缓存一段时间


    希望这对某人有所帮助,如果你有任何好的建议,请让我知道。

    我知道这是一个老问题,但下面是为我解决它的方法

    在您的hibernate.cfg.xml中,确保具有正确的!DOCTYPE。。。其内容应如下:

    Statement statement = session.connection().createStatement();
    ResultSet rs = statement.executeQuery("select * from MyHibernateClass");// 7ms
    List<MyHibernateClass> result = convert(rs);// executes in 20ms
    
    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    

    我遇到了一个事件,我的应用程序总是使用查询结果集中的每一行。通过使用下面的setFetchSize方法设置获取大小,我发现速度提高了40倍。(性能改进包括添加计数查询。)


    做这件事时要小心;我的数据集大约有100行,它的范围是web请求生命周期中的一段时间。如果您有更大的数据集,则在将数据返回Java堆之前,您将在该数据存在的期间内吃掉Java堆。

    在我发现DOCTYPE标记在
    hibernate.cfg.xml
    *mapping object*.hbm.class

    确保
    hibernate.cfg.xml

    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    
    
    
    并将xml.class与

    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    
    

    现在,我花了1-2秒来执行任何查询。

    任何其他SQL Server遇到类似问题的人都可以在JDBC查询字符串中使用
    sendStringParametersAsUnicode=false
    ,如以下回答所示:


    如果准备语句参数不使用Unicode,并且希望利用
    varchar
    字段上的索引作为准备语句的参数,这可能会有所帮助。

    为什么您真的担心7ms?;)谢谢你提出一个澄清的问题。我更愿意使用hibernate版本,但7000毫秒的执行时间是不可接受的。我知道这个线程很旧,但为了更新,我遇到了相同的问题,但使用SQL Server,结果是hibernate打印的SQL和使用驱动程序发送的SQL是不同的。默认情况下,使用MSSQL驱动程序将查询作为存储过程作为RPC调用发送1。我添加了额外日志信息的输出,日志记录似乎会减慢系统的速度。2.在测试中的一个hql查询之前,我尝试执行另一个hql查询,但没有产生任何差异