- PR -

【C#.NET】パフォーマンスを改善したいです。

投稿者投稿内容
あき
ベテラン
会議室デビュー日: 2003/07/23
投稿数: 72
投稿日時: 2004-07-06 12:45
こんにちわ。

SQL ServerとC#.NETで、データベースアプリケーションを開発しております。
データベースアクセスの効率がでなくて悩んでいます。

処理としては、DataSetを1件更新して、その後にデータベースを1件更新する処理を1万回繰り返しています。ちなみに、処理時間は、1万件で5分かかりました。
他に手はないかと、DataSetを100件更新して、データベースを100件更新する処理に変えてみたところ(つまり100回更新です)、処理時間が1分までになりました。

もうこれ以上速くする手立てはないものでしょうか?

ご意見をお聞かせください。
よろしくおねがいします。

えムナウ
大ベテラン
会議室デビュー日: 2004/06/10
投稿数: 187
お住まい・勤務地: 東京
投稿日時: 2004-07-06 13:29
バッチ的な更新であればUPDATE文で更新したりストアドプロシージャを使う方法も考えてみてください。
Top > @IT会議室 > Database Expert 会議室 の方が詳しい話が聞けるかもしれません。

更新内容(SQL等)も書き込んだほうがいいと思いますよ。
_________________
えムナウ Microsoft MVP for Visual Developer - C#,2005/01-2007/12
えムナウのプログラミングのページ Blog1 Blog2
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-07-06 14:00
引用:

あきさんの書き込み (2004-07-06 12:45) より:

もうこれ以上速くする手立てはないものでしょうか?


 パフォーマンス改善は、どこに時間がかかっているのかを計測することが第一歩です。
 次に、改善がどれくらい有効かを検証します。その為には、今やっている処理がなぜ時間がかかるのか、改善案ではなぜ速くなるのかを理解し、知識として蓄えます。

 この2つの手順をとばしても、近い将来同じ問題で時間をつぶすだけです。


 今回はなぜ速くなったか。DataSetの更新内容をデータベースに反映する為にDbDataAdapter.Update()メソッドを使用したと思います。これは内部で
1.データベースに接続する
2.データテーブル最初から最後まで検査して、更新のある行を抜き出す
3.更新のある行に対して、UPDATE, INSERT, DELETEを実行する
4.データベースとの接続を切る
という作業をしています。ここで、2と3は、データの数に依存します。1と4はUpdateメソッドの発行回数に依存します。1データずつUpdateを発行すると、1〜4を1万回繰り返したわけです。100データずつ行ったということは、1と4は100回、2と3は1万回行ったわけです。1と4の実行回数が1/100になったことで、実行時間が1/5になっています。
あき
ベテラン
会議室デビュー日: 2003/07/23
投稿数: 72
投稿日時: 2004-07-06 17:34
えムナウさん、ご意見ありがとうございました。
ストアドプロシージャですね。
これだと接続切断も1回にできますから、改善が見込めそうです。

Jittaさん、ご意見ありがとうございました。
説得力のある解説に圧倒されました。
切羽詰って目先のことばかり考えていましたが、やはり建設的に進めるのがいちばんですね。

貴重なご意見をありがとうございました。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-07-06 18:18
引用:

あきさんの書き込み (2004-07-06 17:34) より:
これだと接続切断も1回にできますから、改善が見込めそうです。


一応、単純に接続回数という意味では、先にOpenしておいてからUpdateを繰り返すことでまとめることもできます。まあ、それ以外の意味も大きいでしょうけど。

1件を10000回と、100件を100回に関しては、対象レコードの検索もそれなりに関係あるんではないでしょうか?
※まあ、接続の繰返しと比べたら無視できる「かも」知れませんが。

1件を10000回→10000件中1件の検索を1万回実行
100件を100回→10000件中100件の検索を100回実行

でもやっぱり接続ですかね(接続プールを使用した場合の接続の負荷がどの程度か全く知らないんですが、一件処理毎にやっていればさすがに大きいと思います)。
一度、接続を一回にしたものも試してみたらどうでしょう。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-07-06 19:29
引用:

なちゃさんの書き込み (2004-07-06 18:18) より:

1件を10000回→10000件中1件の検索を1万回実行
100件を100回→10000件中100件の検索を100回実行


 1万件から1件検索を100回を100回かな???
 100行同じ変更なら、1回の検索で100件のデータを返す、でいいのでしょうが、DbDataAdapter.Updateメソッドなら、1件ごとではないでしょうか?


〜〜〜〜〜
 あと、おそらく、SQLのプリコンパイルも関係あるかと。Oracleですと、直前のSQLは実行計画が立っていますから、それを利用します。値をSQL文に埋め込まず、Parameterを使うのは、プリコンパイルを有効にする為ですね。SQL Serverについても、同じようなことをやっていると思います。

 だとすると、INSERT, UPDATE, DELETEごとにDataTable(とDataRow)を複製して、3回に分けて実行する方が、データによっては速いかもしれません。また、分ける段階で変更の必要がないものをはじきますから・・・でも、オブジェクトを複製するオーバーヘッドが大きいかな?
 インデックスでアクセスできる行を、変更内容ごとに並べ替えできるのなら、それを行って、かつ変更のない行についてはDataTableから取り除いておくと、よいような???
あき
ベテラン
会議室デビュー日: 2003/07/23
投稿数: 72
投稿日時: 2004-07-07 15:17
初めての技術なので、うまく説明できるかわかりませんが...;
今回の開発では、アーキテクチャとしてWEBサービスを使用しています。
設計方針として、コネクションプールを圧迫しないようにという理由で接続時間を最小限にしています。
※聞いた話ですが、この3階層システムでは、フロントヤード(クライアント→アプリケーションサーバー)・バックヤード(アプリケーションサーバー→データベースサーバー)ともに同じコネクションプールを使用しているため、リソースの占有が起きないようにするためとのことです。
ですから、接続を一回にした長いトランザクションは効果はあると思いますが、方針から考え直す必要がでてきますので(悲)、最終手段にしたいです。
INSERT, UPDATE, DELETEごとにDataTable(とDataRow)を複製して、3回に分けて実行するのは、実験してみたいと思います。
開発メンバーからもこのようなアイディアがありました。
NAL-6295
ぬし
会議室デビュー日: 2003/01/26
投稿数: 966
お住まい・勤務地: 東京
投稿日時: 2004-07-07 15:53
引用:

Jittaさんの書き込み (2004-07-06 19:29) より:

 だとすると、INSERT, UPDATE, DELETEごとにDataTable(とDataRow)を複製して、3回に分けて実行する方が、データによっては速いかもしれません。また、分ける段階で変更の必要がないものをはじきますから・・・でも、オブジェクトを複製するオーバーヘッドが大きいかな?
 インデックスでアクセスできる行を、変更内容ごとに並べ替えできるのなら、それを行って、かつ変更のない行についてはDataTableから取り除いておくと、よいような???



その方法でしたら、複製しなくても、

コード:
    DataAdapter.Update(DataTable.Select("", "", DataViewRowState.Deleted))
    DataAdapter.Update(DataTable.Select("", "", DataViewRowState.ModifiedCurrent))
    DataAdapter.Update(DataTable.Select("", "", DataViewRowState.Added))



でもいいと思います。

スキルアップ/キャリアアップ(JOB@IT)