2016-04-28 34 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。 –

相關問題