为什么hibernate在获取较少数量的行时速度较慢?

时间:2016-04-28 20:26:13

标签: hibernate jdbc hibernate-mapping

我正在关注此处列出的hibernate教程http://docs.jboss.org/hibernate/orm/5.1/quickstart/html_single/#tutorial-native

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

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

我发现,与我的自定义JDBC和java对象映射实现相比, hibernate非常慢,这很奇怪。当获取的行数低于10000时会发生这种情况。例如,使用my方法获取10-100行需要3-18ms,而hibernate需要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();

}

1 个答案:

答案 0 :(得分:1)

1:基于你的hibernate属性,Hibernate将尝试重新创建数据库模式,这需要查询元数据,计算差异,应用差异(如果需要),这不是在直接JDBC中完成的。任何比较都无效。

2:多种技术之间的任何性能比较都需要一个预热期,因为有各种各样的幕后设置(连接到数据库,解析SQL语句,解释元数据等)。您还包括一个连接池大小,根据您使用hibernate的方式,可能会在以后为休眠带来不公平的优势。

3:您没有包含Hibernate映射文件或带有JPA注释的对象。即使你的基本SQL语句没有连接,如果你在对象中定义了关系,Hibernate会考虑到这一点,所以再次,可能不是一个公平的比较。

4:在启动期间,Hibernate将连接到数据库,加载映射文件/对象,确保所有对齐以及数据库和持久性对象都可用。如果您的命名查询语法错误,包含表/列名称等,则应进行标识。它还需要你的持久性对象,并使用一些动态字节生成/ CGLIB来创建对象(至少在工作表之下),而不仅仅是普通的POJO(至少我们认为它是这样)。

5:当要求Hibernate获取数据时,它将创建SQL语句并将结果直接绑定到对象中。所以显然有些开销虽然一旦完成它会更有效率。在您的直接JDBC循环中,每次您需要搜索以查找getLong,getString,getDate等返回的列时,而不是计算一次列数,然后使用直接索引。就在这里可能是罪魁祸首,Hibernate需要一点时间才能有效地设置所有内容,然后由于创建对象的效率而最终超过原始JDBC。

6:作为一个抽象层,Hibernate总是比编写良好的直接JDBC应用程序慢(这个例子不是这样)。但是,开发时间越少,错误越少,代码的整体质量应该更好。你只需要在其限制范围内工作。