データベースへの連続挿入について – プログラミング – Home

データベースへの連続挿入について
 
通知
すべてクリア

[解決済] データベースへの連続挿入について


ぷっきー
 ぷっきー
(@ぷっきー)
ゲスト
結合: 16年前
投稿: 2
Topic starter  

【環境】
VC++ 2008
MFC
SQL SERVER

現在、大量のデータをODBC経由で、
データベースに連続挿入をする際、

CDatabase::ExecuteSQL(INSERT INTO~

をデータの数だけ呼び出して実行しているのですが、
どうも処理に時間がかかってしまい困っています。
(100万レコードに対して、3~4時間ほど)

なんとか、処理性能を上げたいと思っているのですが、
ストアド、ExecuteSQLを用いる以外に何か方法はありますでしょうか。
よろしくお願いいたします。


引用未解決
トピックタグ
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

書かれている情報だけでは何とも。

レコード単位でSQLを発行しているのであれば、
SQL SERVERとのやり取りも100万回起こっているわけで
やり取り分のオーバーヘッドに関してはデータの受け渡しが
必要であれば、省略しようが無いと思います。
テーブルからの抽出結果を挿入するとかならサーバー内で完結する事も
可能でしょうけれど、外部からのデータ投入に関しては難しいのではないかと。

テーブルの構成もキーの設定も何も書かれていませんので
あてずっぽになりますけれど、投入されるデータによっては
キーの設定を外しておいてデータの投入が終わってから
一気にキーを張った方が早いケースもあるかもしれません。
後は、投入順番を旨く調整すると少しは早くなるとかあるかも。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

こういうやり方が良いかどうかはわかりませんけれど、
アイディアレベルの話として
一旦、CVS形式のファイルに落としておいて
データベースに直接インポートするとかしたら
少し早くなりませんかねぇ。
それくらいしか思いつかないです。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

 SQL文で考えるなら、ぷっきーさんが決めずにお客様に決めてもらうのがいい
と思います。
 まず、VCで組まずにSQL文をじかに実行して動作を確認するのが
大事だと思います。
 SQL SERVERをお客様が構築されたのであれば、クライアントの用意していると思います。
一度お客様とどんなSQL文にするか相談するのも一つの方法だと思います。
 


返信引用
never where
 never where
(@never where)
ゲスト
結合: 16年前
投稿: 1
 

もしかしたら、AUTO COMMITがONになっている可能性もあるので、トランザクションを利
用してみるのはどうでしょう?
SQLを実行する前に CDatabase::BeginTransを、終了時にCDatabase::CommitTransを発行
するだけです。

SQLite3の話ですが、1万行程度の挿入に1時間程度かかっていたのが十数秒にまで短縮
しました。


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

100万レコードに対して3時間としても、1レコードは 10ms程度です。

ExecuteSQL()では、SQL文字列と処理結果をクライアント・サーバ間でやりとり
しますので、通信時間だけでも数ミリsecは食います(CPUやHDDに比べて、LAN間
やりとりは遅い)。

100万レコード分のSQL文字列の量を考えてみてください。
ものすごい文字数でしょ、それだけでも遅くなって仕方ないわけです。
いかに通信量を減らすかが勝負です。

その意味で、
> データベースに直接インポートするとかしたら
は有効だと思います。

もしかして、トランザクションを使用する場合は、コミットするまで、
クライアント-サーバ間通信が発生しない?
そうであるなら、
> もしかしたら、AUTO COMMITがONになっている可能性もあるので、トランザク
> ションを利用してみるのはどうでしょう?
も有効な気がします。


返信引用
ぷっきー
 ぷっきー
(@ぷっきー)
ゲスト
結合: 16年前
投稿: 2
Topic starter  

みなさん、貴重なご意見、ありがとうございました。
非常に参考になりました。

CDatabase::BeginTrans、CDatabase::CommitTrans
はすでに対策済みであったため、直接インポートの
案を検討してみたいと思います。

ご教授くださり、ありがとうございました。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> 100万レコード分のSQL文字列の量を考えてみてください。
> ものすごい文字数でしょ、それだけでも遅くなって仕方ないわけです。

DBプログラミングはただでさえ疎く、C++でなんて一度もやったことがないのですが、
SQL 文字列も毎回送らなければならないんですか?
SQL 文は1回だけ送っておいて、あとはパラメータだけ送信するようなわけにはいかな
いんでしょうかね?


返信引用
ももんが
 ももんが
(@ももんが)
ゲスト
結合: 18年前
投稿: 38
 

1レコードのフィールド数と大体のサイズは
どのくらいなんでしょ?

試してみたいところです。

サイズ次第で時間はかなり違ってきそうです。


返信引用
ももんが
 ももんが
(@ももんが)
ゲスト
結合: 18年前
投稿: 38
 

1000000件 * 1000バイトだと1GB(位かな?)ですから
それだけのファイル転送時間がかかるとして
ファイル転送してサーバ側でインポートする
時間以上にはどうしようもありませんが
10万件位だとどうなんでしょ?


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

説明がうまくなかったようです。
問題なのは、SQL文字列を送ってから応答待ち時間があるということです。

インポートなら、100万レコードを一気に垂れ流しでいいわけです。
・100万レコードの送信時間
が、SQLでINSERT INTOだと、1レコードごとに追加完了&応答待ちに
なりそうという話です。
・(1レコードの送信時間 + レコード追加時間 + 応答時間) * 100万


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

BULK INSERT とか使うのかなぁ。


返信引用
ももんが
 ももんが
(@ももんが)
ゲスト
結合: 18年前
投稿: 38
 

bunさんの
>100万レコードに対して3時間としても、1レコードは 10ms程度です。
に対してのレスではなかったので嫌みのような回答になっていました。

>サイズ次第で時間はかなり違ってきそうです。
>10万件位だとどうなんでしょ?
が本意です。

失礼しました。


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

ももんがさん
いえいえ、全く嫌みなどとは思っていません。

自分で自分の発言を読み返してみて、うまい説明じゃないなぁ(笑)
と思ったので、言葉を変えてみました。

単なるアホです(汗)


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました