【问题标题】:How to optimize the insert query time using hiberate?如何使用休眠优化插入查询时间?
【发布时间】:2017-02-08 08:20:18
【问题描述】:

我有大约 140 万条数据记录,但插入它们需要 3 个多小时。我似乎找不到它的问题。

我阅读并从身份更改为序列。它只改进了一点点,但仍然需要很长时间才能完成插入。

我正在使用:

  • 休眠 5
  • 春天 4
  • mssql 2014
  • 野蝇 10

applicationContext-hibernate.xml

<tx:advice id="txAdvice">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <tx:method name="*_TransNew" propagation="REQUIRES_NEW" />
            <tx:method name="*_NoTrans" propagation="NEVER" />

            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />

            <tx:method name="generate*" propagation="REQUIRED" />
            <tx:method name="get*" propagation="REQUIRED" />
            <tx:method name="is*" propagation="REQUIRED" />

            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>


    <!-- ensure that the above transactional advice runs for any execution of 
        an operation defined by the following -->
    <aop:config>
        <aop:pointcut id="demoServiceOperations"
            expression="execution(* com.test.*.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="demoServiceOperations" />
    </aop:config>

<bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2012Dialect</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.jdbc.batch_size">50</prop>
                <prop key="hibernate.order_inserts">true</prop>
                <prop key="hibernate.order_updates">true</prop>

                <prop key="hibernate.c3p0.min_size">5</prop>
                <prop key="hibernate.c3p0.max_size">20</prop>
                <prop key="hibernate.c3p0.timeout">1800</prop>
                <prop key="hibernate.c3p0.max_statements">50</prop>


            </props>
        </property>         
    </bean>

Umts.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Nov 22, 2016 11:36:21 AM by Hibernate Tools 5.2.0.Beta1 -->
<hibernate-mapping>
    <class name="com.test.domain.Umts" table="TBLDM_UMTS" schema="dbo" catalog="DEMO" optimistic-lock="version" dynamic-update="true">
        <id name="umtsId" type="java.lang.Integer">
            <column name="UMTS_ID" />
            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
                <param name="optimizer">pooled-lo</param>
                <param name="increment_size">1</param>
                <param name="sequence_name">UMTS_SEQ</param>
            </generator>
        </id>
        <property name="cid" type="java.lang.Integer">
            <column name="CI" not-null="true" />
        </property>
        <property name="channelNo" type="java.lang.Integer">
            <column name="UARFCN" />
        </property>
        <property name="signalStrength" type="java.lang.Double">
            <column name="EC_IO" precision="53" scale="0" />
        </property>
        <property name="sc" type="java.lang.Integer">
            <column name="SC" />
        </property>
        <property name="latitude" type="java.lang.Double">
            <column name="LATITUDE" precision="53" scale="0" />
        </property>
        <property name="longitude" type="java.lang.Double">
            <column name="LONGITUDE" precision="53" scale="0" />
        </property>
         <property name="mcc" type="java.lang.Integer">
            <column name="MCC" not-null="true" />
        </property>
        <property name="mnc" type="java.lang.Integer">
            <column name="MNC" not-null="true" />
        </property>
        <property name="recvDate" type="date">
            <column name="RECV_DATE" length="10" />
        </property>
        <property name="recvTime" type="time">
            <column name="RECV_TIME" length="16" />
        </property>
    </class>
</hibernate-mapping>

服务类:

public void process(List<Umts> umtsList)
{
  for (int i = 0; i < umtsList.size(); i = i + PropertiesUtil.MAX_COMMIT_COUNT)
        {
            int min = i;
            int max = i + PropertiesUtil.MAX_COMMIT_COUNT;

            if (max > umtsList.size())
            {
                max = umtsList.size();
            }

            createUmts_TransNew(umtsList.subList(min, max));
        }
}
    @Override
        public void createUmts_TransNew(Collection list) 
        {
            // TODO Auto-generated method stub

            umtsDAO.saveAll(list);  
        }

DAO 类:

@Transactional
    public void saveAll(Collection collection)
    {
        log.debug("** save all");
        try
        {
            if (collection != null && collection.size() > 0)
            {
                for (Object obj : collection)
                {
                    sessionFactory.getCurrentSession().saveOrUpdate(obj);                   
                }
            }
        }
        catch (RuntimeException re)
        {
            log.error("** save all failed", re);
            throw re;
        }
    }

** 已编辑 连接池在这里起作用吗?意味着连接池对性能有帮助吗?我需要将 jar 文件添加到 wildfly 10 还是应用程序本身?

【问题讨论】:

  • 为什么用 Java 做?可以使用批量插入吗?
  • @ScaryWombat 不是我做的批量插入吗?
  • 看起来createUmts_TransNew(umtsList.subList(min, max)); 在你的for 循环中
  • @ScaryWombat 我认为这实际上就是我正在做的事情,除非我的 transnew 传播不起作用?

标签: java sql-server spring hibernate wildfly-10


【解决方案1】:

首先,尝试增加pooled-lo 的值。由于您将其设置为 1,因此不会进行优化/池化 - 因为需要获取的每个 ID 都需要调用数据库以获取实际值。如果您有更大的增量大小,hibernate 将预先获取/保留一个 ID 块以用于新实体,而无需每个实体往返。

不确定您发布的代码是如何执行的,但我假设您将它们按顺序插入到单个线程中。你可以:

  • 使用线程池,其中每个线程从列表/队列中获取一些要插入的项目。
  • 由一个线程插入到单个事务中的项目的大小理想情况下与配置的休眠批处理大小相同,以再次最小化往返。
  • 确保池中的线程数与连接池大小相当,这样在等待连接时就不会阻塞工作线程。
  • 确保连接池大小对于服务器可以承受的负载是合理的,并使用良好的连接池(例如HikariCP)。这是一个有趣的writeup on connection pool size.

【讨论】:

  • 增量大小是否应该跟随db中的缓存值?
  • MSSQL 序列上的缓存值决定了保存在内存中的序列值的数量,并且仅在每 X 次使用时写入它的系统表。当 hibernate 请求时,MSSQL 仍会将序列增加 1,而不管序列的缓存属性如何。所以不,它不应该与休眠内部序列 ins 在 DB 上的处理方式是透明的一样 - 在使用时它只会看到增量为 1。
  • 我还是迷路了。即使更改了值,性能仍然相同。我还需要将 HikariCP 添加为 Wildfly 10 中的库还是添加到我的应用程序本身?
  • 没有简单的方法将 HikariCP 用作容器管理的数据源,如果可能的话,只会带来额外的开销。您是否尝试过其他建议(使用多个线程插入数据)?如果您使用多个线程提供数据并持续保持所有连接处于使用状态,则无需更改池。
  • 我实际上使用 c3p0-0.9.1.1.jar 作为我的连接池(请参阅更新的 applicationContext-hibernate.xml)。但性能也没有任何变化。
猜你喜欢
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
相关资源
最近更新 更多