ストアドプロシージャがWebから呼び出されると遅くなり、Management Studioから速くなる


97

Webアプリケーションから呼び出されるたびにめちゃくちゃにタイムアウトするストアドプロシージャを使用しています。

Sqlプロファイラーを起動して、タイムアウトした呼び出しをトレースし、最終的に次のことを見つけました。

  1. 同じ引数を使用して、MS SQL Management Studio内からステートメントを実行すると(実際、プロシージャコールをSQLプロファイルトレースからコピーして実行しました)、平均5〜6秒で終了します。
  2. しかし、Webアプリケーションから呼び出された場合、30秒以上(トレース)かかるため、私のWebページは実際にはそれまでにタイムアウトになります。

私のWebアプリケーションに独自のユーザーがいるという事実は別として、すべてが同じです(同じデータベース、接続、サーバーなど)また、Webアプリケーションのユーザーを使用してスタジオで直接クエリを実行してみましたが、6を超えることはありません秒。

何が起こっているのかを知るにはどうすればよいですか?

トレースが遅延が実際の手順にあることを明確に示しているため、BLL> DALレイヤーまたはテーブルアダプターを使用しているという事実とは何の関係もないと想定しています。それは私が考えることができるすべてです。

編集私はこのリンクでADO.NET ARITHABORTがtrueに設定していることを発見しました-ほとんどの場合これは良いですが、これは時々起こります、そして推奨される回避with recompile策はストアドプロシージャにオプションを追加することです。私の場合、動作していませんが、これに非常に似ていると思います。誰もがADO.NETが他に何をしているのか、または仕様をどこで見つけられるのか知っていますか?


1
これは、返されるデータの量に関連している可能性がありますか?
Barry Kaye

@Barry:いいえ、Management Studioで同じ手順(トレースからコピーしたもの-同じパラメーターを意味します)を実行しているため、6秒以内に実行されます。
iamserious

@Jayantha:ポイントはspが遅いということではありませんが、ado.netとsqlの間で何かが遅いということです。spがどのように変化するかはわかりません。
iamserious

2
SPは、image / text / varchar(max)列など、大量のデータを返しますか?クライアントで消費するデータの量は膨大になり、多くの時間がかかります。SSMSは、より効率的な問題でこれらの結果セットを切り捨てます。
Tim Schmelter、2011

回答:


79

過去にも同様の問題が発生したことがあるので、この質問の解決策を見たいと思っています。OPに関するAaron Bertrandのコメントにより、Webから実行するとQueryタイムアウトが発生しましたが、SSMSから実行すると超高速になり、質問は重複していませんが、状況に応じて答えが適切になる場合があります。

本質的には、SQL Serverのキャッシュされた実行プランが破損している可能性があります。あなたはウェブサーバーで悪い計画にぶつかっていますが、ARITHABORTフラグの設定が異なるため、SSMSは別の計画に到達します(そうしないと、特定のクエリ/ストアドプロシージャに影響を与えません)。

ADO.NETがT-SQLストアドプロシージャを呼び出すとSqlTimeoutException発生するのを参照してください。


これらはいくつかの興味深いリードであり、それらについての詳細を読み、数回戻ってきます。
iamserious

44
こんにちは、キャッシュDBCC DROPCLEANBUFFERSをクリアDBCC FREEPROCCACHEしてトリックを行いました!実行計画が何らかの理由で破損しているか、更新されていなかったと思います。私はそれが永久的な修正であるか疑わしいです、それが一度破損する可能性がある場合、それは再びそれを行うことができます。だから私はまだもっともらしい原因を調べています。Webアプリが再び動作するようになったので、プレッシャーを感じる必要はありません。どうもありがとう。
iamserious

2
@iamserious-ありがとうございます!ストアドプロシージャを変更した後、タイムアウトの問題が発生しました。次に、上記の2つのDBCCコマンドを実行し、問題を解決しました。
インダストラー、

5
@マンジスト:これは複雑な問題であるため、特効薬はありませんが、問題の原因となっているクエリでヒントを使用しOPTIMIZE FORたりOPTION(Recompile)クエリのヒントを試したりできます。この記事では、問題について詳しく説明します。Entity Frameworkがクエリを生成している場合、この投稿はクエリヒントをクエリに追加する方法を提供するようです。
StriplingWarrior 2015

8
すべての実行プランをクリアするDBCC DROPCLEANBUFFERSおよびDBCC FREEPROCCACHEを実行する代わりに、問題のあるストアドプロシージャを削除して再作成できます。
jnoreiga 2015年

50

また、クエリがWebからゆっくりと実行され、SSMSで高速に実行されていることも経験しました。その結果、問題がパラメータースニッフィングと呼ばれるものであることがわかりました。

私の修正は、sprocで使用されるすべてのパラメーターをローカル変数に変更することでした。

例えば。変化する:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
SELECT * FROM Table WHERE ID = @param1 

に:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
DECLARE @param1a int
SET @param1a = @param1
SELECT * FROM Table WHERE ID = @param1a

奇妙に思われるが、それは私の問題を修正しました。


3
うわー、私は同じ問題を抱えていて、これがうまくいくとは信じていませんでしたが、うまくいきました。
Lac Ho

1
ゼーン、これで問題が完全に修正されるのか、それとも戻ってくるのか知っていますか?ありがとうございました!
Lac Ho

1
この変更を行って以来、ストアドプロシージャの速度に問題はありませんでした。
Zane 2013年

1
うわー、私の問題も修正されました!これはSQLサーバーのバグである必要があります。MSSQLが内部でローカルに変換して巨大なパフォーマンスを得ることができるのに、なぜSQLライターにこの愚かなループを強制的に通過させるのですか?
HerrimanCoder 2015年

3
プロシージャを変更すると新しい実行プランが作成されるため、ソリューションは実際には入力変数をローカル変数にコピーするのではなく、新しい実行プランの生成を強制するだけです(承認されたソリューションで説明)。
ガーランド教皇

10

スパムではありませんが、他の人にとって期待できる有用な解決策として、私たちのシステムは高度なタイムアウトを見ました。

を使用してストアドプロシージャを再コンパイルするように設定しようとしたところsp_recompile、1つのSPの問題が解決しました。

最終的にはSPのタイミングアウト、使用することによって、その前にやったことがなかったその多くはなかったというのも大きい数があったDBCC DROPCLEANBUFFERSDBBC FREEPROCCACHEタイムアウトの発生率が大幅に急落しました-隔離出現がまだありますが、私は計画の再生を疑うところ、いくつかは、撮影ですしばらくの間、および一部のSPは本当にパフォーマンスが低く、再評価が必要な場合があります。


1
これをありがとう。sp_recompileコマンドを使用して再コンパイルするプロシージャにマークを付けるDBCC DROPCLEANBUFFERSと、とDBCC FREEPROCCACHEの違いがなくなりました。
Steve

4

WebアプリケーションがSPを呼び出す前に行われた他のいくつかのDB呼び出しがトランザクションを開いたままにしているのでしょうか?これが、このSPがWebアプリケーションによって呼び出されたときに待機する理由である可能性があります。Webアプリケーションでの呼び出しを分離(新しいページに配置)して、Webアプリケーションでの以前のアクションがこの問題を引き起こしていることを確認します。


1
こんにちは@Tundeyです。通話を切り分けましたが、まだ約30秒かかり、タイムアウトします。ですから、コミュニケーションの間の何かである必要があると思いますか?
iamserious

1

ストアドプロシージャ(私の場合はテーブル関数)を再コンパイルするだけでうまくいきました


1

@Zaneのように、それはパラメータスニッフィングが原因である可能性があると述べました。私は同じ動作を経験し、プロシージャの実行プランとspのすべてのステートメントを続けて調べました(すべてのステートメントをプロシージャからコピーし、パラメータを変数として宣言し、変数に同じ値を割り当てました)パラメータがありました)。ただし、実行計画は完全に異なって見えました。spの実行には3〜4秒かかり、まったく同じ値を持つ行のステートメントがすぐに返されました。

実行計画

少しグーグルで調べた後、その動作について興味深い読みを見つけました。アプリケーションで遅い、SSMSで速い?

プロシージャをコンパイルするとき、SQL Serverは@fromdateの値が変更されたことを認識しませんが、@ fromdateの値がNULLであるという仮定の下でプロシージャをコンパイルします。NULLとのすべての比較でUNKNOWNが生成されるため、実行時に@fromdateにこの値が残っている場合、クエリは行をまったく返すことができません。SQL Serverが最後の真実として入力値を取得する場合、テーブルにまったくアクセスしない定数スキャンのみで計画を構築できます(クエリSELECT * FROM Orders WHERE OrderDate> NULLを実行して、この例を確認してください)。 。ただし、SQL Serverは、実行時に@fromdateの値に関係なく、正しい結果を返すプランを生成する必要があります。一方、すべての価値に最適な計画を立てる義務はありません。したがって、行が返されないことを前提としているため、SQL Serverはインデックスシークを解決します。

問題は、nullのままにできるパラメーターがあり、それらがnullとして渡された場合、デフォルト値で初期化されることでした。

create procedure dbo.procedure
    @dateTo datetime = null
begin
    if (@dateTo is null)
    begin
        select @dateTo  = GETUTCDATE()
    end

    select foo
    from dbo.table
    where createdDate < @dateTo
end

に変更した後

create procedure dbo.procedure
    @dateTo datetime = null
begin
    declare @to datetime = coalesce(@dateTo, getutcdate())

    select foo
    from dbo.table
    where createdDate < @to
end 

それはまた魅力のように働きました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.