Java

MyBatisで複数のレコードを一括で更新する方法

【MyBatis】大量データを一括更新する

MyBatisで大量データを一括で更新する方法を紹介します。

使用するDBMS(データベース管理システム)により一括更新の方法が異なるため、本記事では「Oracle」「PostgreSQL」「SQL Server」「MySQL」それぞれの方法を紹介します。

※今回の例では、下記のUPDATE文を一括更新しています。

[通常のUPDATE文]

<!-- 更新 -->
<update id="update">
    UPDATE
        userinfo
    SET
        name = #{name}
        ,address = #{address}
        ,phone = #{phone}
        ,update_date = CURRENT_TIMESTAMP
    WHERE
        id = #{id}
</update>

スポンサーリンク

「PostgreSQL」と「SQL Server」で一括更新する方法

MyBatisを利用してPostgreSQLとQL Serverで一括更新する方法は次のとおり。

<!-- 一括更新 -->
<update id="bulkUpdate">
    <foreach collection="userList" item="item" separator=";">
        UPDATE
            userinfo
        SET
            name = #{item.name}
            ,address = #{item.address}
            ,phone = #{item.phone}
            ,update_date = CURRENT_TIMESTAMP
        WHERE
            id = #{item.id}
    </foreach>
</update>

「Oracle」で一括更新する方法

MyBatisを利用してOracleで一括更新する方法は次のとおり。Oracleの場合は、「BEGIN」と「;END;」が必要です。

<!-- 一括更新 -->
<update id="bulkUpdate">
    BEGIN
    <foreach collection="userList" item="item" separator=";">
        UPDATE
            userinfo
        SET
            name = #{item.name}
            ,address = #{item.address}
            ,phone = #{item.phone}
            ,update_date = CURRENT_TIMESTAMP
        WHERE
            id = #{item.id}
    </foreach>
    ;END;
</update>

「MySQL」で一括更新する方法

MyBatisを利用してMySQLで一括更新する方法は次のとおり。MySQLの場合は、ELT()とFIELD()を使用して複数のレコードをまとめて更新します。

<!-- 一括更新 -->
<update id="bulkUpdate">
UPDATE
    userinfo
SET
    name = ELT(FIELD(id,
        <foreach collection="userList" item="item" separator=",">
            #{item.id}
        </foreach>
        ),
        <foreach collection="userList" item="item" separator=",">
            #{item.name}
        </foreach>
    )
    ,address = ELT(FIELD(id,
        <foreach collection="userList" item="item" separator=",">
            #{item.id}
        </foreach>
        ),
        <foreach collection="userList" item="item" separator=",">
            #{item.address}
        </foreach>
    )
    ,phone = ELT(FIELD(id,
        <foreach collection="userList" item="item" separator=",">
            #{item.id}
        </foreach>
        ),
        <foreach collection="userList" item="item" separator=",">
            #{item.phone}
        </foreach>
    )
    ,update_date = CURRENT_TIMESTAMP
WHERE
    id IN
    (
        <foreach collection="userList" item="item" separator=",">
            #{item.id}
        </foreach>
    )
</update>

測定結果(MySQL)

「1件ずつ更新する」場合と「複数のレコードをまとめて更新」する場合で、どのくらいの差がでるのか測定してみました。

測定結果は次の表のとおり。今回の測定で使用したDBMSは「MySQL」、一括更新は1000件ずつまとめて更新しています。また測定で使用しているPCのメモリは8GBです。

更新方法 1万件 10万件 100万件
1件ずつ更新 8秒 1分3秒 10分31秒
一括更新 (1000件ずつまとめて更新) 2秒 22秒 3分17秒

測定した結果、1件ずつ更新するよりも複数のレコードをまとめて更新した方が圧倒的に早いという結果になりました。