11

私のチームは私に「それは問題ではない」と言っていて、それは私をイライラさせているので、私はあなたのプロ/達人からの確認/説明が必要です:)

背景:メインの MVC3 / .Net4 Web アプリで使用されている SQL Server 2008 があります。任意の時点で約 200 人以上の同時ユーザーがいます。サーバーは非常に大きな打撃を受けており (ロック、タイムアウト、全体的な速度低下)、キャリアを通じて、また最後の MS 認定クラスで学んだことを適用しようとしています。これらは私たち全員が掘り下げてきたものであり (「SQL 接続を閉じる STAT」)、これらの「ささいなこと」は 1 つだけで違いが生じるわけではなく、最終的には合計されることをチームに説明しようとしています。

以下がパフォーマンスに影響を与えるのか、それとも単に「ベストプラクティス」なのかを知る必要があります

1.「USING」キーワードの使用。 彼らのコードのほとんどは次のようなものです:

public string SomeMethod(string x, string y) {
    SomethingDataContext dc = new SomethingDataContext();
    var x = dc.StoredProcedure(x, y);
}

USING がリソースをより速くクローズ/解放することを彼らに伝えようとしている間:

using (SomethingDataContext dc = new SomethingDataContext()) {
    var x = dc.StoredProcedure(x, y);
}

彼らの主張は、コードの実行が完了した後、GC は適切なクリーンアップを行うため、USING は大きな影響を与えないというものです。真か偽か、その理由は?

2. 接続プール

接続プールを設定すると、Web サイト (少なくとも .Net w/MSSQL) を大幅に高速化できるといつも聞いていました。web.config の接続文字列に以下を追加することをお勧めします。

..."プーリング=True;最小プール サイズ=3;最大プール サイズ=100;接続タイムアウト=10;"...

彼らの主張は、.Net/MSSQL はすでに舞台裏で接続プールをセットアップしており、web.config に入れる必要はないというものです。正しいか間違っているか?プーリングが既にセットアップされている場合、最適なパフォーマンスのためにプーリングを追加する必要があると他のすべてのサイトが言うのはなぜですか?

3. DB の呼び出し回数を最小限に抑える

デフォルトの .Net MVC プロジェクトに付属している Role/Membership プロバイダーは便利です。便利で、ほとんどの作業を自動的に行ってくれます。しかし、これらの人は真剣に使用しUsersInRoles()ており、グローバル変数のように自由に使用しています (このメソッドが呼び出されるたびに DB にヒットします)。すべてのページロードで事前にすべてのロールをロードする「ユーザーオブジェクト」を作成し(GUIDなどの他のユーザーのものと一緒に)、ユーザーがロールを持っているかどうかをこのオブジェクトに照会します。

Web サイトの他の部分には、200 回以上ループし、パスごとに 20 ~ 30 回の SQL クエリを実行する FOR ステートメントがあります = 4,000 回を超えるデータベース呼び出し。何とか数秒でこれを行いますが、私がやりたいのは、20-30 の DB 呼び出しを 1 つに統合して、1 つの呼び出しを 200 回 (各ループ) 行うことです。しかし、SQL プロファイラーはクエリに「0 秒」かかったと言っているため、サーバーがこれらの多数の DB クエリを処理できるほど高速で小さいという議論があります。

私の考えでは、「ええ、これらのクエリは高速に実行されていますが、SQL サーバー全体のパフォーマンスが低下しています。」これが要因になるのでしょうか?私は何も心配していませんか、それともサーバー全体のパフォーマンスの問題に (重大な) 影響を与えている要因なのでしょうか?

4. その他のコードの最適化

最初に頭に浮かぶのはStringBuilder、単純な文字列変数 vs の使用です。なぜStringBuilder(特にループで)使用する必要があるのか​​ は理解していますが、彼らはそれは問題ではないと言っています.10k以上の行を書く必要があるとしても、彼らの主張はパフォーマンスの向上は問題ではないということです.

全体として、私たちが学び、掘り下げてきたすべてのこと (「スコープを最小化します!」) は、実際のパフォーマンスの向上を伴わない「ベスト プラクティス」にすぎないのでしょうか? それとも、すべてが実際の/測定可能なパフォーマンスの低下に寄与しているのでしょうか?

編集*** すべての回答に感謝します!あなたの回答に基づいて、新しい (5 番目の) 質問があります。実際、彼らは「USING」を使用していません。接続プーリングが自動的に行われている場合、GC が発生するまでプールからの接続が拘束されますか? SQL サーバーへの接続を開くたびに、サーバーに少し負担がかかり、速度が低下する可能性はありますか?

あなたの提案に基づいて、a) サーバーが遅い、b) サーバーが接続を閉じていない、c) プロファイラーが 0 秒で実行されたと言っている、遅い接続から来ている可能性があります。

皆さんの助けに本当に感謝しています。再度、感謝します

4

9 に答える 9

5

コードを分岐し、変更を加えて、現在のコードベースに対してベンチマークとプロファイリングを行います。そうすれば、あなたの主張を裏付ける証拠が得られます。

ご質問については、次のとおりです。

  1. を実装するクラスは常に手動で破棄する必要がありますIDisposable。GC は実際には dispose を呼び出しませんが、クラスがファイナライザーも実装している場合はファイナライザーを呼び出しますが、ほとんどの実装ではアンマネージ リソースのみをクリーンアップします。

  2. .NET フレームワークが既に接続プールを行っていることは事実です。デフォルトが何であるかはわかりませんが、接続文字列の値は、変更できるようにするためのものです。

  3. SQL ステートメントの実行時間は、話の一部にすぎません。SQL プロファイラーでは、データベース エンジンがクエリを実行するのにかかった時間だけが表示されます。そこに欠けているのは、Web サーバーが接続するのにかかる時間です。データベースサーバーから結果を受け取るので、クエリは高速かもしれませんが、クエリをバッチ処理することで多くの IO とネットワーク遅延を節約できます。

  4. これは、プロファイリングを行って、文字列ビルダーで連結によって使用される余分なメモリを証明するのに適したものです。

于 2013-02-13T22:34:35.030 に答える
4

ああ。確かに、GCにデータベース接続を閉じさせることはできません。GCは長い間起こらないかもしれません...時々数時間後。変数がスコープから外れるとすぐには発生しません。ほとんどの人はIDisposableusing(){}構文を使用します。これは素晴らしいですが、少なくとも何か、どこかでconnection.Close()を呼び出す必要があります。

于 2013-02-13T22:41:39.950 に答える
3
  1. IDisposable を実装し、管理されていないリソースを保持するオブジェクトは、GC 中に dispose が呼び出されることを保証するフィニライザーも実装します。問題は、それが呼び出されるときです。GC はそれを行うのに多くの時間がかかる可能性があり、その前にそれらのリソースが必要になる可能性があります。 . Using は、使い終わったらすぐに dispose を呼び出します。

  2. webconfig でプーリングのパラメーターを変更できますが、現在はデフォルトでオンになっているため、デフォルトのパラメーターをそのままにしておくと、何も得られません。

  3. クエリの実行にかかる時間だけでなく、アプリケーション サーバーとデータベース間の接続時間も考慮する必要があります。同じコンピューター上にある場合でも、オーバーヘッドが追加されます。

  4. StringBuilder は、ほとんどの Web アプリケーションのパフォーマンスに影響を与えません。同じ文字列に 2 回連結する場合にのみ重要ですが、読みやすいので使用することをお勧めします。

于 2013-02-13T22:33:30.953 に答える
2

ここには2つの別々の問題があると思います。

  1. コードのパフォーマンス
  2. SQL Server データベースのパフォーマンス

SQLサーバー

SQL Server を監視していますか? デッドロックの原因となる実行中のクエリを具体的に知っていますか?

デッドロックに関するこの記事を読み、SQL Server で実際に何が起こっているかを調べるために、すばらしいWho is activeをインストールすることを検討します。Brent Ozarによる sp_Blitz のインストールも検討してください。これにより、データベースで何が起こっているかについての優れたアイデアが得られ、その問題を最初に修正するためのツールが得られます。

その他のコードの問題

頭の中で他のコードの問題についてコメントすることはできません。したがって、最初に SQL サーバーを調べます。

覚えて

  1. モニター
  2. 問題を特定する
  3. プロフィール
  4. 修理
  5. 1に行く
于 2013-02-13T22:37:12.900 に答える
1

ここで他の人が言ったことを繰り返すリスクを冒して、これがこの問題に関する私の2cです

まず、あなたは慎重に戦いを選ぶべきです...あなたがそれらの1つを証明することに失敗するとすぐにそれは終わり、彼らの観点からは彼らは正しく、あなたは'間違っています。また、美しいコードが醜い赤ちゃんだと言われるのを好む人はいないので、外交的になると思います。「これは遅い」とは言わず、「これをさらに速くする方法を見つけました。 「....(もちろん、あなたのチームは完全に合理的である可能性があるので、私自身の経験にも基づいています:)したがって、最初に取り組むには、上記の4つの領域のいずれかを選択する必要があります。

私のお金は#3にあります。1、2、4は違いを生む可能性がありますが、私自身の経験ではそれほどではありません-しかし、#3で説明したことは、貧弱な古いサーバーの千枚の紙切れによる死のように聞こえます!クエリはパラメータ化されているためキャッシュされるため、おそらく高速に実行されますが、プロファイラーの「0秒」は900ミリ秒になる可能性があることに注意する必要があります。そして物事は遅くなり始めます。これは、ロックの主な原因になる可能性もあります。これらのネストされたクエリのそれぞれが同じテーブルに何度もヒットしている場合、実行速度に関係なく、言及したユーザー数によって、競合が発生することは確実です。SQLを取得してSSMSで実行しますが、クライアント統計を含めると、実行時間だけでなく、クライアントに返送されるデータの量も確認できます。これにより、どのようなオーバーヘッドが関係しているかをより明確に把握できます。

これを証明できる唯一の方法は、他の人が述べているようにテストと測定をセットアップすることですが、サーバーでもプロファイリング(ロック、IOキューなど)を実行して、それを示すことができるようにすることも確実です。高速であるだけでなく、サーバーへの負荷も少なくなります。

5番目の質問に触れると-わかりませんが、(を使用して)自動処理されないSqlConnectionはまだ「アクティブ」としてカウントされ、プールからは利用できなくなっていると思います。そうは言っても、接続が実際に何かを行っていない限り、サーバーの接続オーバーヘッドはかなり低くなりますが、SQLパフォーマンスカウンターを使用してこれを再度証明できます。

幸運を祈ります。どうやって乗るかを知るのが待ちきれません。

于 2013-02-14T00:24:40.403 に答える
1

ええと、私は教祖ではありませんが、提案があります。彼らがあなたが間違っていると言ったら、「証明してください! テストを書いてください! 4000 回の呼び出しが 200 回の呼び出しと同じくらい高速であることを示してください。サーバーへの影響も同じです!」

他のことも同じです。あなたが正しいことを彼らに証明させる立場にない場合は、あなたの言っていることが正しいことを示す明確で十分に文書化されたテストで、彼らが間違っていることを証明してください.

彼らが自分のサーバーから収集した確固たる証拠でさえ、彼らが見て調べることができるコードでさえオープンにしないなら、あなたはそのチームであなたの時間を無駄にしているかもしれません.

于 2013-02-13T22:34:05.950 に答える
0

私は最近、Webアプリケーションと電子メールプロバイダー間の相互作用のバグに対処していました。電子メールが送信されたときに、プロトコルエラーが発生しました。しかし、すぐにではありません。

エラーが発生したのはSmtpClientインスタンスが閉じられたときのみであり、これは破棄されたときに発生し、SmtpClientガベージコレクション中にのみ発生したことがわかりました。

そして、「送信」ボタンがクリックされてから2分かかることがよくあることに気づきました...

言うまでもなく、コードはインスタンスとインスタンスusingの両方のブロックを適切に実装するようになりました。SmtpClientMailMessage

賢者に一言...

于 2013-02-13T22:45:10.213 に答える
0

1 は上で十分に対処されています (ただし、適切に破棄することに同意し、それが良い習慣であることがわかりました)。

2 は、SQL Server 接続がプーリングに関して個別に構成されていた以前のバージョンの ODBC から少し引き継がれています。以前はデフォルトではありませんでした。今はデフォルトです。

3 と 4 に関しては、4 は SQL Server のパフォーマンスに影響を与えませんStringBuilder。確かに、UI 内のプロセスを高速化するのに役立つ可能性があります。これにより、SQL リソースをより速く閉じる効果があるかもしれませんが、負荷は軽減されません。 SQL Server で。

私にとって、3 は集中するのに最も論理的な場所のように思えます。データベース接続をできるだけ早く閉じ、呼び出しをできるだけ少なくするようにしています。を使用している場合は、すべてをまたは何か (リスト、配列など)LINQにプルして、それを操作し、必要な UI 構造を構築しながら、その hokum の前に接続を解放します。IQueryable

そうは言っても、プロファイラーでもう少し質の高い時間を過ごす必要があるようです. 各実行にかかった時間を見るのではなく、プロセッサとメモリの使用量を見てください。それらが速いからといって、「ハングリー」な実行ではないというわけではありません。

于 2013-02-13T22:51:31.100 に答える
0

using 句は単なる構文糖衣であり、本質的にやっている

try
{
    resouce.DoStuff();
}
finally
{
     resource.Dispose()
}

Dispose はおそらく、オブジェクトがガベージ コレクションされるときに呼び出されるでしょうが、それはフレームワーク プログラマが Disposeパターンを適切に実装した場合に限られます。したがって、ここであなたの同僚に対する議論は次のとおりです。

i) すべてのフレームワーク プログラマーが使い捨てのパターンを実装するのが賢明であるとは限らないため、使用する習慣を身につけたら、管理されていないリソースを解放するようにします。

ii) はい、GC は最終的にそのオブジェクトを消去しますが、オブジェクトの古さによっては時間がかかる場合があります。第 2 世代の GC クリーンアップは、1 秒に 1 回だけ実行されます。

要するに:

  1. 上記を参照

  2. はい、プーリングはデフォルトでtrueに設定され、最大プールサイズは100に設定されています

  3. あなたは正しいです、間違いなく改善のために推進するのに最適な分野です.

  4. 時期尚早の最適化は諸悪の根源です。1位と3位を先に獲得。SQL プロファイラーとデータベース固有のメソッドを使用します (インデックスの追加、最適化、デッドロックの監視など)。

  5. はい、そうかもしれません。最善の方法はそれを測定することです - パフォーマンス カウンター SQLServer: General Statistics – User Connections を見てください。ここにその方法を説明する記事があります。

常に改善を測定し、証拠なしにコードを変更しないでください!

于 2013-02-13T22:35:38.710 に答える