MySQL TIPS 6 ストアドプロシージャで指定した数のダミーデータを用意する3
ユーザ変数の文字列バッファ操作に時間が掛かっているので、一旦テンポラリーテーブルに格納してからgroup_concatでまとめて結合という手段を取ってみた。
phpで言うところの配列(array)に格納しておいて、あとでimplodeでまとめて結合するというテクニックですね
<?php for($i=0;$i++;$i<100000){ $str.=$i; } echo $str
<?php for($i=0;$i++;$i<100000){ $str[]=$i; } echo implode('',$str);
解説
- ストアドプロシージャ中でテンポラリーテーブルを使っているので、事前に同名のテンポラリーテーブルがある場合はDROP TABLE IF EXISTSを使って初期化している。DROP TABLE IF EXISTはテーブルが既に存在していた場合にWARNINGを吐くので、前後でset session sql_notesを使って警告を無効化している。
- GROUP CONCATの最大長が巨大になるので、buf_sizeにクエリー長を計算した値を格納しgroup_concat_max_lenを設定
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 '); set session sql_notes=0; drop temporary table if exists t_values; set session sql_notes=1; create temporary table t_values (val varchar(255)); set @buf_size:=length(@sql); while @num <= end_num do set @buf:=concat('(',replace(value,'@num',@num),')'); insert into t_values VALUES ( @buf ); set @buf_size:=@buf_size+length(@buf)+1; set @num:=@num + step; end while; set session group_concat_max_len=@buf_size; set session max_allowed_packet=@buf_size; set @sql:= concat(@sql,(select group_concat(val) from t_values)); 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 (5.52 sec)
めっちゃ早くなった。
8/4追記
- max_allowed_packet不足になっていたので設定を追加
- max_allowed_packetがread_onlyなので困った
- メモリを消費し過ぎなので、折衷案を検討中