【SQL】大量のinsert処理DBに投げたときに時間を短縮する方法
それは突然起きた・・・
こんにちはユウスケです。
ちょっと前に、大きめのCSVをDBにインポートする処理を仕事で作りました。
処理自体はGoでCSVを1行ずつ読み取ってデータベースにinsertするというシンプルなものでしたが・・・
とてつもなく遅い
という問題が発生しました。
行数的に14万行程度だったのですが、なんと2時間近くかかりました。
原因
結論から書くと、原因は1行のinsert毎にコミットしてたからです。
恥ずかしながら今の今まで意識したことがなかったのですが、SQLを流した時、実際に反映するコミット処理はとても重い処理のようで、これが毎行やることでDB側の負荷が増大してました。
しかも1行で2つのテーブルにまたがって一気にinsertする仕組みなので、コミットの負荷がとてつもない事になってました。
ちなみに最初、「毎回レコードの多いテーブルをselectしてるから重いのかな?」と思い、select文を流す回数を減らし効率化しましたが、それでもあまり変わりませんでした。
対処法
最初、Multipulinsertを使って複数行をまとめてコミットしようとしました。
が、GoのORMパッケージはgormを使っているのですが、これにはMultipulinsertが存在しなく・・・コミットのタイミングを調整することが出来ませんでした。
結局トランザクションを使って全部まとめてコミットする。というところに落ち着きました。
この結果、なんと5分弱で完了しました。実に1時間55分の短縮です。
なんというスピード。今までの時間は何だったんでしょうか。っていうレベルです。
14万行まとめてコミットでもこのスピードなので満足ですが、コミット時の負荷を考えるなら1万行毎にコミットでもいいかもしれませんね。