- PR -

ADO.NETで、データベースの初回更新が遅い

投稿者投稿内容
むーみん
常連さん
会議室デビュー日: 2005/06/23
投稿数: 41
投稿日時: 2008-01-30 17:55
burton999さん、かずくんさん、どうもありがとうございます。

かずくんさん、すみません。
私の間違いでした。
Connectionのプロパティは、Friendアクセスでした。
C#でやってみたら、Internalになりました。
同じアセンブリ内からならアクセスできるというところは、両方同じ感じですね。

同じdllファイルになるので、そのまま使用できると思います。

更新の呼び出しは、以下のように行っています。
コード:

Using trnScope As New System.Transactions.TransactionScope

' 親テーブルレコード更新
Using da親 As New 親TableAdapter
da親.Update(データセットのインスタンス)
End Using

' 子テーブルレコード更新
Using da子 As New 子TableAdapter
da子.Update(データセットのインスタンス)
End Using

trnScope.Complete()
End Using


このUpdateメソッドを呼び出した時に、それぞれのDataAdapterがインスタンス化されて、さらにそのDataAdapterの初期化処理のときにConnectionも初期化されていました。

早速お二人に教えていただいた方法を試してみます。


[ メッセージ編集済み 編集者: むーみん 編集日時 2008-01-30 18:56 ]
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2008-01-30 18:28
引用:

かずくんさんの書き込み (2008-01-30 17:11) より:
SQL Server 2000だからなのかな?
試してみたら、AdapterのConnectionはinternalなプロパティになったんだけどなぁ。


ごめん、Visual Basic 2005て書いてたね。気づきませんでした。

[/quote]
また、Connection共有しとかないと、ひとつのトランザクションで親・子を更新できない気がするんだけど、気のせい?
[/quote]
TransactionScopeを使うんだね。
勉強になりました。
むーみん
常連さん
会議室デビュー日: 2005/06/23
投稿数: 41
投稿日時: 2008-01-30 19:48
結果から申し上げますと、速度はとっても早くなりました。
初回も、二度目以降も、変わらなくなりました。
今後のためにも、本当にありがとうございます。

一応、検証した内容は、
まず、burton999さんのおっしゃったように、画面の起動時(コンストラクタ)で、ローカル変数のSqlConnectionを6つくらい作りました。以下のような感じです。

コード:
    Using cn As New SqlConnection(DBConnectString)
        cn.Open()
        Using cn1 As New SqlConnection(DBConnectString)
            cn1.Open()
            Using cn2 As New SqlConnection(DBConnectString)
                cn2.Open()
                ・
                ・
                ・
                cn2.Close()
            End Using
            cn1.Close()
        End Using
        cn.Close()
    End Using



それから、かずくんさんのおっしゃって下さった感じで、更新時の処理を以下のように直しました。

コード:
    Using trnScope As New Transactions.TransactionScope

        Using cn As New SqlConnection(DataCommon.DBConnectString)
            cn.Open
            ' 親テーブルレコード更新
            Using da親 As New 親TableAdapter
                da親.Connection = cn
                da親.Update(データセットのインスタンス)
            End Using

            ' 子テーブルレコード更新
            Using da子 As New 子TableAdapter
                da子.Connection = cn
                da子.Update(データセットのインスタンス)
            End Using
            cn.Close
        End Using

        trnScope.Complete()
    End Using



ただ、更新処理前に接続をオープンしてあげないと、速度は速くならなかったです。
DataAdapterが、接続の開閉をちゃんと自動でやってくれるので、便利に思ってDataAdapterを使用するときは、今まで書かなかったのですが、速度が改善されないため、試しにOpenしてみたら、とても変わりました。

とても勉強になりました。

それと、burton999さんにはなんだか申し訳ないのですが、接続を十分作ってプールしておくコードをコメントアウトして実行してみたのですが、速度は変わらず早かったです。
一応、検証したことはご報告しようと思いました。

ただ、本当にとても感謝しております。
お二人とも、どうも大変ありがとうございました。

自分でもう少し調べて、何か分かったことがあったら載せたいと思います。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2008-01-30 20:59
ちょっと変なほうにいってるような…
接続プールのプール数を多くしたいなら、
接続文字列でプールの最小サイズを少し増やせばいいと思います。

ただ、いずれにしても、起動後の本当の最初の接続には(接続プールの準備には)
時間がかかりますが。

今回速くなったのは接続を多く準備したからではなく、接続をひとつしか
使用しなくなったからだと思います。
正確には、これにより、分散トランザクションが回避されています。

最初が遅かったのは、初めての分散トランザクションの処理に時間が
かかっていたからではないですか?

--追記
すみません、接続の多数確保をしなくても早くなったとかかれてましたね。
なので、速くなった理由は分散トランザクションを使用しなくなったためではないか、
という部分だけ読んでください。
※最初の(初めての)分散トランザクションはそれなりに遅かった記憶があります。


[ メッセージ編集済み 編集者: なちゃ 編集日時 2008-01-30 21:03 ]
むーみん
常連さん
会議室デビュー日: 2005/06/23
投稿数: 41
投稿日時: 2008-01-30 21:44
なちゃさん、どうもありがとうございます。

接続プールの問題ではなかったのですね。
それでたくさんプールしてもしなくても速度が変わらない理由がわかりました。

私が今回投稿した、元々の問題は、最初の接続を確立する準備にかかる時間が原因でした。
そこから、自分が作成した更新プログラムで、初回更新時が遅いと感じていた理由はその接続プールの問題だと思ってしまっていました。
なので、話題を接続にもっていってしまいました。

この問題の原因は、分散トランザクションのせいだったのですね。
それだと納得のいくことが確かにあります。
みなさんにご指摘頂いてコードを修正する前の状態のとき、コードをステップ実行すると、子テーブルのUpdateメソッドのところで時間がかかっていました。

なちゃさんにご指摘を受けて、前の状態の更新処理のコードで、さらに一度に更新するテーブルを4つに増やして動作を確認してみたら、やっぱり2つめのUpdateメソッドで時間がかかりました。

そういうことなのですね。本当にありがとうございます。

なちゃさんに教えていただいたことを元に、自分で少し動作確認をして、またご報告したいと思います。
むーみん
常連さん
会議室デビュー日: 2005/06/23
投稿数: 41
投稿日時: 2008-01-31 12:45
分散トランザクションについて、以下のページを読んでみたところ、単語や意味することがよく分からないところも結構ありましたが、わかるところはなちゃさんのおっしゃるとおりで、動作確認をしたところ全くそのとおりでした。
今までは、分散トランザクションについてよくわからないまま、TransactionScopeを使用していました。
「トランザクションの昇格」について、勉強になりました。

http://msdn2.microsoft.com/ja-jp/library/ms229978(VS.80).aspx

TransactionScopeを使用して複数テーブルを更新しても、必ずしもMSDTCが起動して分散トランザクションに昇格するわけではない。
ただし、オープンした状態の一つの接続を使用する必要がある。(なるべくそうする)

ということが分かりました。
ただ。。書いててきっと、みなさんが知っていたことだろうなと思うと恥ずかしいです。。
私は勉強不足ですみません。

それと、一度分散トランザクションに昇格すると、同一プログラムでなくても、同一アプリケーション(ソリューション?)内なら分散トランザクションへの昇格はないようで、更新の速度は初回も二回目変わりませんでした。
同一ソリューション内。
Aというプログラムの更新処理実行で分散トランザクションに昇格。
Bというプログラムの更新処理実行で分散トランザクションを使用しても、早い。

みなさん、どうも大変ありがとうございました。

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