MySQL における Bulk Update

またハマったのでメモ。

begin;
delete from t;
insert into t select ...;
commit;

とかやると、完了までの間、他の更新がブロックされてしまう。更新系と参照系が同一のウェブサーバで動いていたりすると、サービス全体がその間利用不可能になる、ということでもある。したがって

for ($id_start = 0; $id_start < $id_max; $id_start += BLOCK_SIZE) {
  $dbh->begin_work;
  $dbh->do(
    $dbh->printf(
        'delete from t where %d<=id and id<%d',
        $id_start,
        $id_start + BLOCK_SIZE,
    ),
  );
  $dbh->do(
    $dbh->printf(
       'insert into t select ... where %d<=id and id<%d',
       $id_start,
       $id_start + BLOCK_SIZE,
    ),
  );
  $dbh->commit;
}

みたく分割すべき。