2016-04-28 84 views
2

我正在按照这里列出的hibernate教程http://docs.jboss.org/hibernate/orm/5.1/quickstart/html_single/#tutorial-native为什么hibernate在获取较少的行数时速度较慢?

我修改了使用本地mysql作为数据库的代码。之后,我用10000行填充数据库表。

我比较了两种类型的DB读取的延迟 - 一种是通过hibernate原生查询;其他通过直接JDBC并从ResultSet创建对象。

我发现很奇怪,看到与我的自定义JDBC和Java对象映射实现相比,hibernate非常慢。当获取的行数低于10000时会发生这种情况。例如,使用我的方法获取10-100行需要3-18ms,而休眠需要280-320ms左右。但是,当我尝试获取> 10K行时,hibernate变得高效。

有人可以请解释什么hibernate做这导致这么多的延迟?

我的hibernate.cfg.xml看起来像下面

<?xml version='1.0' encoding='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
<session-factory> 

    <!-- Database connection settings --> 
    <property name="connection.url">jdbc:mysql://localhost:3306/fquick-task-manager?useSSLx`=false</property> 
    <property name="connection.username">root</property> 
    <property name="connection.password"/> 

    <!-- JDBC connection pool (use the built-in) --> 
    <property name="connection.pool_size">15</property> 

    <!-- SQL dialect --> 
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 

    <!-- Disable the second-level cache --> 
    <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property> 

    <!-- Echo all executed SQL to stdout --> 
    <property name="show_sql">true</property> 

    <!-- Drop and re-create the database schema on startup --> 
    <property name="hbm2ddl.auto">update</property> 

    <mapping resource="org/hibernate/tutorial/hbm/Event.hbm.xml"/> 

</session-factory> 
</hibernate-configuration> 

我的测试功能看起来像下面

public void testBasicUsage() { 

    // Using JDBC 
    Session session = sessionFactory.openSession(); 
    session.beginTransaction(); 
    String queryStr = ""; 
    try { 
     long start = System.currentTimeMillis(); 
     Statement statement = ((SessionImpl) session).connection().createStatement(); 
     queryStr = "select * from Events where EVENT_ID < 10"; 
     ResultSet rs = statement.executeQuery(queryStr); 
     List<Event> events = new ArrayList<Event>(); 
     while (rs.next()) { 
      Long eventId = rs.getLong("EVENT_ID"); 
      String title = rs.getString("title"); 
      Date myDate = rs.getDate("EVENT_DATE"); 
      Event event = new Event(eventId,title ,myDate); 
      events.add(event); 
     } 
     long end = System.currentTimeMillis(); 
     long timeTaken = end - start; 
     System.out.println("Query took " + timeTaken + "ms"); 

    } catch (SQLException e) { 
     System.out.println("Error in statement creation"); 
    } 
    session.getTransaction().commit(); 
    session.close(); 

    // Using Hibernate 
    session = sessionFactory.openSession(); 
    session.beginTransaction(); 
    queryStr = "select * from Events where EVENT_ID > 20 & EVENT_ID < 30"; 
    long start3 = System.currentTimeMillis(); 
    session.createSQLQuery(queryStr).list(); 
    long end3 = System.currentTimeMillis(); 
    long timeTaken3 = end3 - start3; 
    System.out.println("Query took " + timeTaken3 + "ms"); 
    session.getTransaction().commit(); 
    session.close(); 

} 
+0

我试过这两件事情。获取相同的一组行,以及不同组的10行,50行,100行组合。结果是一样的。在数据库中花费的时间在每次5ms以内。休息是在ORM中度过的。我有兴趣了解休眠情况下的时间分配。在持久化上下文中保存对象需要多少时间,制作对象有多少时间,以及为什么在行数较少的情况下执行速度较慢。 –

回答

0

1:根据您的休眠性的判定时,Hibernate会尝试重新创建数据库模式,它需要查询元数据,计算差异,应用差异(如有必要),这不是在直接JDBC中完成的。任何比较都是无效的。因为存在各种幕后设置(连接到数据库,解析SQL语句,解释元数据等),所以多种技术之间的任何性能比较都需要预热时间。你还包括一个连接池的大小,这取决于你如何使用休眠,可能会给休眠带来不公平的优势。

3:您没有包含Hibernate映射文件或带有JPA批注的对象。即使您的基本SQL语句在这里没有连接,但如果您已经定义了对象中的关系,Hibernate将会考虑到这一点,所以再次,可能不是一个公平的比较。 4:在启动过程中,Hibernate将连接到数据库,加载映射文件/对象,确保所有内容对齐,并确保数据库和持久对象可用。如果您命名了语法错误的查询,列出了表名/列名等,则应该对其进行标识。它也需要你的持久化对象,并做一些动态字节生成/ CGLIB的东西来使对象(至少在表单下)不仅仅是一个普通的POJO(至少我们认为它是这样)。 5:当Hibernate被要求获取数据时,它会创建SQL语句并将结果直接绑定到对象中。所以显然有些开销,但一旦完成,它会更有效率。在你的直接JDBC循环中,每当你需要搜索找到getLong,getString,getDate等返回的列时,而不是一次找出列号,然后使用直接索引。就在这里,可能的罪魁祸首是,Hibernate花费一点时间来高效地设置一切,然后由于创建对象的效率最终超过了原始JDBC。 6:作为一个抽象层,Hibernate总是比写得很好的直接JDBC应用程序(这个例子不是)要慢。但是,开发时间较少,错误较少​​,代码的整体质量应该更好。你只需要在其限制内工作。

+0

,我不知道为什么一切都变得粗暴,对此感到抱歉。 –

+0

感谢您的回复。第1点仅在应用程序启动时有效,因此不会影响查询时间。对于第3点,这里是我的课程https://ideone.com/UhwEOM和我的映射文件https://ideone.com/BqzJzs,它没有任何关联。 hibernate确实做了很多事情,例如在持久化上下文中保存对象,使用反射来查找对象字段和其他东西。我想知道通过休眠获得更少行(即10行)的时间分布。 hibernate里的哪个构造使用了多少时间,即使是较小的行,也需要300ms。 –

相关问题