MyBatis-spring + Java を使用しました。1 回のトランザクションで 10000 件を超えるレコードをテーブルに挿入する必要があります。それを行うために、私はマッパーを使用しました:
<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>
そして、このステートメントに List を渡します。2000 ~ 3000 レコードの処理は非常に遅くなりますが、10000 レコードは 4 分以上挿入されます (タイムアウト間隔を長くする必要があります)。同じ 10000 レコードが PgAdmin を介して同じ DB に 10 秒未満で挿入されます。この操作の処理をトレースしてみたところ、ボトルネックが見つかりました
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);
}
}
StatementHandler は数分、prepareStatement は数分で計算されます。なぜそれが起こるのか理解しています。各レコードに 9 つのフィールドを持つ 10000 レコード。これらの 100k フィールドはすべて、パラメーターとしてステートメントに挿入する必要があります。そして、どうすればこのプロセスを加速できますか?
アップデート:
sqlFactory と @Transactional の "BATCH" モードを使用してバッチ保存を実装します。これは、mybatis-spring XML 構成の構成です。
<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>
次に、「バッチ」メソッドを実装しました。
@Transactional
public void saveBulk(List<Quote> quotes) {
for(Quote q:quotes) {
mapper.save(q);
}
}
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" 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>
それは速く働いています