2016-04-04 8 views
1

私はMyBatis-spring + Javaを使用しました。 1回のトランザクションでテーブルに10000を超えるレコードを挿入する必要があります。それを行うために、私はマッパーを使用しました:MyBatisバルクオペレータのパフォーマンス

<insert id="saveBulk" parameterType="List"> 
    INSERT INTO "quote" ("id", "mi_id", "timestamp", "open", "close", "low", "high", "volume", "period") 
    VALUES 
    <foreach collection="list" item="item" separator=","> 
     (#{item.key}, #{item.marketInstrumentKey}, #{item.timestamp}, #{item.open}, #{item.close}, #{item.low}, 
     #{item.high}, #{item.volume}, #{item.period}::quote_period) 
    </foreach> 
</insert> 

そしてこのステートメントへのリストを渡してください。 2000〜3000レコードでは非常にゆっくりと処理されますが、10000レコードが4分以上挿入されます(タイムアウト間隔を長くする必要があります)。同じ10000レコードがPgAdmin経由で同じDBに10秒未満挿入されます。私は、この操作の処理を追跡しようとしたとのprepareStatementためStatementHandlerは数分を計算し

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 
    Statement stmt = null; 
    try { 
     Configuration configuration = ms.getConfiguration(); 
     StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 
     stmt = prepareStatement(handler, ms.getStatementLog()); 
     return handler.update(stmt); 
    } finally { 
     closeStatement(stmt); 
    } 
    } 

ボトルネック、そして数分を発見しました。 私は、なぜそれが起こるのか理解しています:各レコードに9フィールドの10000レコード。これらすべての100kフィールドは、パラメータとして文に挿入する必要があります。 このプロセスをどのように加速できますか?

UPDATE:

私はsqlFactoryと@Transactionalの "バッチ" モードで使用して保存したバッチを実装しています。 "バッチ" 方法次に

<bean id="sqlBatchTemplate" class="org.mybatis.spring.SqlSessionTemplate"> 
     <constructor-arg index="0" ref="sqlSessionFactory"/> 
     <constructor-arg index="1" value="BATCH"/> 
    </bean> 

    <bean id="quoteBatchMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> 
     <property name="mapperInterface" value="tafm.dataaccess.mybatis.mapper.QuoteMapper"/> 
     <property name="sqlSessionFactory" ref="sqlSessionFactory"/> 
     <property name="sqlSessionTemplate" ref="sqlBatchTemplate"/> 
    </bean> 
    <bean id="dataAccessBatch" class="tafm.dataaccess.DataAccess"> 
     <property name="quoteMapper" ref="quoteBatchMapper"/> 
    </bean> 

、私が実装しています: これはMyBatisのスプリングXMLコンフィグレーションの設定です - :

@Transactional 
    public void saveBulk(List<Quote> quotes) { 


     for(Quote q:quotes) { 
      mapper.save(q); 
     } 
    } 

マッパーエンティティ引用のためのXMLマッパーであります

<insert id="saveBulk" parameterType="List"> 
    INSERT INTO "quote" ("id", "mi_id", "timestamp", "open", "close", "low", "high", "volume", "period") 
    VALUES 
    <foreach collection="list" item="item" index="index" separator=","> 
     (#{item.key}, #{item.marketInstrumentKey}, #{item.timestamp}, #{item.open}, #{item.close}, #{item.low}, 
     #{item.high}, #{item.volume}, #{item.period}::quote_period) 
    </foreach> 
</insert> 

速いです。

+0

ご使用のデータベースサーバーを教えてください。 –

+0

私はPostgreSQL 9.4を使用しました –

+0

以下のメソッドを試してみてください。それはあなたのために働くかもしれません。 –

答えて

1

このようなことができます。 1000.so 1000年の記録で間隔を使用してコード上記

public void insertBulkData(List<Item> list) 
    { 
     int total = list.size();   
     int interval = 1000; 
     int from = 0; 
     int to = 0; 
     while (to <= total) 
     { 
      from = to == 0 ? 0 : to; 
      to = (to + interval) <= total ? (to + interval) : total; 
      saveBulk(list.subList(from, to)); 
      if (to == total) 
       break; 
     } 
    } 

Javaファイルで
Mapper.xmlは

<insert id="saveBulk" parameterType="List"> 
    INSERT INTO "quote" ("id", "mi_id", "timestamp", "open", "close", "low", "high", "volume", "period") 
    VALUES 
    <foreach collection="list" item="item" separator=","> 
     (#{item.key}, #{item.marketInstrumentKey}, #{item.timestamp}, #{item.open}, #{item.close}, #{item.low}, 
     #{item.high}, #{item.volume}, #{item.period}::quote_period) 
    </foreach> 
</insert> 

もこの間隔を変更することができtime.youに挿入されます。
あなたがinsertBulkData(リスト)を呼び出す必要があります。
これはあなたに役立つことを願っています。

+0

ありがとうございます。このトリックは、この特定の問題を解決します。残念ながら、それは主要な問題を解決しません:パフォーマンス。だから、私は実際の一括挿入(1000レコード)にこのアプローチを使用することはお勧めしません。このアプローチの代わりにバッチ実行タイプを使用することをお勧めします –

+0

バッチ実行..任意のサンプルコードを取得できます。 –

+0

私は最初の質問にセクション「UPDATE」を追加しました。私は、バッチモードを実装する方法を明確にしようとした –