BULK INSERTで苦しみぬいたテーブルに、またもや事件ですよ、姉さん<やめなさい
実はこれ「ファイルのレコード順番を維持したまま、あーだこーだと処理をして、最終的にあるテーブルへ保存する」という要件だったのですが、300万件超レコードを有するものであることが判り、ムンク状態。ファイルレコード順番を維持したまま、あーだこーだ、の処理部分はおかげさまで完成。あとはテーブルへの保存だったわけですが……。
最初のロジック
INSERT INTO TBLhoge (列いっぱい) select 列いっぱい from hoge;
でした。これだと2万件くらいまでなら余裕。ところが、200万超えた辺りから、トランザクションログを使い切り始める。
「よいでわないか、よいでわないか」とログを切り捨てつつ、がんがん増やす→ある日、ハードディスクを使い切る(笑)
本番サーバーではいけると思うけど、開発段階でこれが起きてるものをそのまま入れるのもどうよ、と「人として~♪」と頭の中によぎりつつ、何とかならんのかい、と悩む事一日。
で、昨日、お風呂で……ひらめいたっ!
プロファイラ見る限り、BULK INSERT ってのはBATCH_SIZEを指定して、その件数で分割してINSERTな処理を走らせてるわけです。なら、テーブル保存時にもこれと同じ事ができれば、トランザクションログは使い切らないはず。運の良いことに、エラーやっちゃってもマスターテーブルにKEY情報を書き込まなければそのデータは参照されないし、定期メンテで殺せるように設計済。そしてデータには、ファイルレコード順番維持のためのID連番が存在しているっ!
「ちゃぁぁんす♪」(by惣流・アスカ・ラングレー)
で、作った処理
wRcnt には ID連番のMAX値
wBcnt は 1 で初期化
INSERT文に" WHERE BETWEEN ID wBcnt AND wBcnt + (BULK INSERT のバッチサイズ - 1 )"をくっつけたSQLを発行
wBcnt は BULK INSERT のバッチサイズで増分
wRcnt < wBcnt になるまでループ
処理も早くなりました。トランザクションも無駄遣いしなくなりました。
これなら500万件来ても大丈夫さっ!(でもね……たぶん……きっと……)