■発想を切り替える

前回壊れて起動しなくなったMySQLを再インストールして/etc/my.cnfのパラメータやら触った。
実際load data infileのインプットファイルサイズは11GBぐらいでたいしたことはない。
問題なのはload中にmysqldが落ちること。
そんなにメモリも食ってないのにエラーも吐かないから何も原因がわからない状況で、このままいくらやってもだめだ。
今更ハードの増強はできない。
だからインプットをコマ切りにしてloadしよう
幸いSHにはtailコマンドとheadコマンドがあるし、動作も速いし書くのも簡単だ(私はCは書けません)。

11GBをこまぎりのファイルにまず分けて、(headコマンドとtailコマンドを駆使)、こまぎりインプットファイルごとにload data infileするSHプログラムを作った。
こんなかんじ
引数は
1:こまぎれにしたいダンプのインプットファイル
2:何件ずつ細切れにするか。改行数ですね
3:load data infileのコマンドでインプットファイルは絶対パス指定にするのでその絶対パスのスラッシュありで指定
4:インプット先のテーブル名

[bash light=”false” toolbar=”false” highlight=”38″ gutter=”false” title=”test.sh”]
#!/bin/bash
#######################################################################
# i split $1 file by $2 number
if test $# -ne 4 ; then
echo "usage :i need 3 arguments ,filename and split line number, input file path (included last / ), table_name"
exit
fi
logfile=$1_split.log
dirpath=$3
linecount=wc $1 |awk '{print $1}'

div=$(( $linecount / $2))
mod=$(( $linecount % $2))
if test $mod -ne 0 ; then

div=$(($div + 1))
fi

sql1="load data infile ‘"
sql2="’ replace into table $4;"
for (( i=0 ;$i < $div; ++i )) ;do
ii=$(( $i + 1))
if test $i -eq 0 ;then
# at first execute head only
head -$2 $1 > $1.1
loadfile=$dirpath$1.1
elif test $i -eq $(( $div – 1 )) ;then
tail -$mod $1 >$1.$ii
loadfile=$dirpath$1.$ii
else
linecountup=$(( ( $i + 1 ) * $2 ))
echo "linecountup"$linecountup
head -$linecountup $1 |tail -$2 >$1.$ii
loadfile=$dirpath$1.$ii
fi
date ‘+%D %H:%M:%S’>>$logfile
mysql -uuser1 -ppassword -q -e "select count(1) from lists" dbname>>$logfile
mysql -uuser1 -ppassword -q -e "$sql1""$loadfile""$sql2" dbname>>$logfile
done
[/bash]

どこが苦労したって、最後、load data infileの-eオプションのvalue値がうまいこと動かなくって、つまり、
$sql1とかの変数にしたのはいいがうまく認識しなくて、変数の中にダブルコーテーションいれてもmysqlコマンドが動かなくて
とても時間を使った。
結局変数はsqlそのまま入れていて、変数をダブルコーテーションで囲めばいいだけの話なのだった。

これで、がりがりファイルを分割してどんどんloadしていく実装ができたわけです。

億いっきには無理でも数十万件ぐらいならさくさくロードしてくれるわけですよ、こんなカジュアルなハードでも。
よかったよかった。
引数にすることによって複数テーブルに対応するのだった。
1億とはいかなくてもあほみたいに件数の多いテーブルは複数あるのです。
次はハードの話へ続く。