【環境】
VC++ 2008
MFC
SQL SERVER
現在、大量のデータをODBC経由で、
データベースに連続挿入をする際、
CDatabase::ExecuteSQL(INSERT INTO~
をデータの数だけ呼び出して実行しているのですが、
どうも処理に時間がかかってしまい困っています。
(100万レコードに対して、3~4時間ほど)
なんとか、処理性能を上げたいと思っているのですが、
ストアド、ExecuteSQLを用いる以外に何か方法はありますでしょうか。
よろしくお願いいたします。
書かれている情報だけでは何とも。
レコード単位でSQLを発行しているのであれば、
SQL SERVERとのやり取りも100万回起こっているわけで
やり取り分のオーバーヘッドに関してはデータの受け渡しが
必要であれば、省略しようが無いと思います。
テーブルからの抽出結果を挿入するとかならサーバー内で完結する事も
可能でしょうけれど、外部からのデータ投入に関しては難しいのではないかと。
テーブルの構成もキーの設定も何も書かれていませんので
あてずっぽになりますけれど、投入されるデータによっては
キーの設定を外しておいてデータの投入が終わってから
一気にキーを張った方が早いケースもあるかもしれません。
後は、投入順番を旨く調整すると少しは早くなるとかあるかも。
こういうやり方が良いかどうかはわかりませんけれど、
アイディアレベルの話として
一旦、CVS形式のファイルに落としておいて
データベースに直接インポートするとかしたら
少し早くなりませんかねぇ。
それくらいしか思いつかないです。
SQL文で考えるなら、ぷっきーさんが決めずにお客様に決めてもらうのがいい
と思います。
まず、VCで組まずにSQL文をじかに実行して動作を確認するのが
大事だと思います。
SQL SERVERをお客様が構築されたのであれば、クライアントの用意していると思います。
一度お客様とどんなSQL文にするか相談するのも一つの方法だと思います。
もしかしたら、AUTO COMMITがONになっている可能性もあるので、トランザクションを利
用してみるのはどうでしょう?
SQLを実行する前に CDatabase::BeginTransを、終了時にCDatabase::CommitTransを発行
するだけです。
SQLite3の話ですが、1万行程度の挿入に1時間程度かかっていたのが十数秒にまで短縮
しました。
100万レコードに対して3時間としても、1レコードは 10ms程度です。
ExecuteSQL()では、SQL文字列と処理結果をクライアント・サーバ間でやりとり
しますので、通信時間だけでも数ミリsecは食います(CPUやHDDに比べて、LAN間
やりとりは遅い)。
100万レコード分のSQL文字列の量を考えてみてください。
ものすごい文字数でしょ、それだけでも遅くなって仕方ないわけです。
いかに通信量を減らすかが勝負です。
その意味で、
> データベースに直接インポートするとかしたら
は有効だと思います。
もしかして、トランザクションを使用する場合は、コミットするまで、
クライアント-サーバ間通信が発生しない?
そうであるなら、
> もしかしたら、AUTO COMMITがONになっている可能性もあるので、トランザク
> ションを利用してみるのはどうでしょう?
も有効な気がします。
みなさん、貴重なご意見、ありがとうございました。
非常に参考になりました。
CDatabase::BeginTrans、CDatabase::CommitTrans
はすでに対策済みであったため、直接インポートの
案を検討してみたいと思います。
ご教授くださり、ありがとうございました。
> 100万レコード分のSQL文字列の量を考えてみてください。
> ものすごい文字数でしょ、それだけでも遅くなって仕方ないわけです。
DBプログラミングはただでさえ疎く、C++でなんて一度もやったことがないのですが、
SQL 文字列も毎回送らなければならないんですか?
SQL 文は1回だけ送っておいて、あとはパラメータだけ送信するようなわけにはいかな
いんでしょうかね?
1レコードのフィールド数と大体のサイズは
どのくらいなんでしょ?
試してみたいところです。
サイズ次第で時間はかなり違ってきそうです。
1000000件 * 1000バイトだと1GB(位かな?)ですから
それだけのファイル転送時間がかかるとして
ファイル転送してサーバ側でインポートする
時間以上にはどうしようもありませんが
10万件位だとどうなんでしょ?
説明がうまくなかったようです。
問題なのは、SQL文字列を送ってから応答待ち時間があるということです。
インポートなら、100万レコードを一気に垂れ流しでいいわけです。
・100万レコードの送信時間
が、SQLでINSERT INTOだと、1レコードごとに追加完了&応答待ちに
なりそうという話です。
・(1レコードの送信時間 + レコード追加時間 + 応答時間) * 100万
BULK INSERT とか使うのかなぁ。
bunさんの
>100万レコードに対して3時間としても、1レコードは 10ms程度です。
に対してのレスではなかったので嫌みのような回答になっていました。
>サイズ次第で時間はかなり違ってきそうです。
>10万件位だとどうなんでしょ?
が本意です。
失礼しました。
ももんがさん
いえいえ、全く嫌みなどとは思っていません。
自分で自分の発言を読み返してみて、うまい説明じゃないなぁ(笑)
と思ったので、言葉を変えてみました。
単なるアホです(汗)