MySQL TIPS 5 ストアドプロシージャで指定した数のダミーデータを用意する2 (失敗編)

以前のエントリーで作ったinsert_generate_seriesを複数INSERT,複数カラムで生成データを使用可能にしてみる

DROP   PROCEDURE insert_generate_series;
delimiter //
CREATE PROCEDURE insert_generate_series(
   IN target    VARCHAR(255) , -- insert対象のテーブル、カラム名を指定
   IN value     VARCHAR(255) , -- valuesを記述 @numがgenerate_seriesで生成された値になる
   IN start_num INT ,          -- 開始値
   IN end_num   INT ,          -- 終了値
   IN step      INT            -- 増分
)
begin
  set @num:= start_num;
  set @sql:= concat('INSERT INTO ',target,' VALUES ');
  while @num <= end_num do
    set @sql:=concat(@sql,' ( ', replace(value,'@num',@num) , ' )');
    if @num <> end_num then
      set @sql:=concat(@sql,',');
    end if;
    set @num:=@num + step;
  end while;
  prepare stmt from @sql;
  execute stmt; 
end;
//
delimiter ;

call insert_generate_series('user(user_name)','concat(md5(@num),@num)',1,100000,1);

Query OK, 100000 rows affected (9 min 43.20 sec);

ちょ、おま、なんだこの遅さは....。生成されたinsert文を実行するのは1秒未満ですが、どうやらINSERT文を生成する際のconcatに時間が掛かっているようです。

  • 冗長になってしまうがループ中のIF文を取り除いてみる
DROP   PROCEDURE insert_generate_series;
delimiter //
CREATE PROCEDURE insert_generate_series(
   IN target    VARCHAR(255) , -- insert対象のテーブル、カラム名を指定
   IN value     VARCHAR(255) , -- valuesを記述 @numがgenerate_seriesで生成された値になる
   IN start_num INT ,          -- 開始値
   IN end_num   INT ,          -- 終了値
   IN step      INT            -- 増分
)
begin
  set @num:= start_num;
  set @sql:= concat('INSERT INTO ',target,' VALUES ');
  while @num < end_num do
    set @sql:=concat(@sql,' ( ', replace(value,'@num',@num) , ' ),');
    set @num:=@num + step;
  end while;
  set @sql:=concat(@sql,' ( ', replace(value,'@num',@num) , ' )');
  prepare stmt from @sql;
  execute stmt; 
end;
//
delimiter ;

call insert_generate_series('user(user_name)','concat(md5(@num),@num)',1,100000,1);

Query OK, 100000 rows affected (4 min 25.48 sec)

なんと2倍!!、驚きの速度に。

DROP   PROCEDURE insert_generate_series;
delimiter //
CREATE PROCEDURE insert_generate_series(
   IN target    VARCHAR(255) , -- insert対象のテーブル、カラム名を指定
   IN value     VARCHAR(255) , -- valuesを記述 @numがgenerate_seriesで生成された値になる
   IN start_num INT ,          -- 開始値
   IN end_num   INT ,          -- 終了値
   IN step      INT            -- 増分
)
begin
  set @num:= start_num;
  set @sql:= concat('INSERT INTO ',target,' VALUES ');
  while @num < end_num do
    set @sql:=concat(@sql,' ( ', replace(value,'@num',@num) , ' ),');
    if @num%100=0 then
      select @num;
    end if;
    set @num:=@num + step;
  end while;
  set @sql:=concat(@sql,' ( ', replace(value,'@num',@num) , ' )');
  prepare stmt from @sql;
  execute stmt; 
end;
//
delimiter ;

call insert_generate_series('user(user_name)','concat(md5(@num),@num)',1,100000,1);

concat時のユーザ変数のバッファが大きくなるほどに遅くなっていくのがわかる。IF文の数が減ったから早くなったのではなくconcatの実行回数が減ったので早くなったらしい。