14

C# Web アプリケーションから挿入クエリを実行しようとしています。SQL Server Management Studio からクエリを実行すると、挿入クエリが完了するまでに約 5 分かかります。アプリケーションから実行すると、30 分 (秒ではなく分) 後にタイムアウトになります。

VS デバッガーから実際の SQL ステートメントを取得し、Mgmt Studio から実行したところ、正常に動作しました。

これはすべて、本番環境ではなく、私の開発環境から実行されています。クエリの進行中は、他の SQL Server アクティビティはありません。開発には SQL Server 2008 R2 を使用しています。MS VS 2010 Express、Asp.Net 4.0。SQL Server 管理スタジオ 10.

答えられなかったこれと同様の質問があります: SQL server timeout 2000 from C# .NET

dbcc useroptions からの SET オプションは次のとおりです。

Option                  MgtStudio      Application
----------------------- -------------- --------------
textsize                2147483647     -1
language                us_english     us_english
dateformat              mdy            mdy
datefirst               7              7
lock_timeout            -1             -1
quoted_identifier       SET            SET
arithabort              SET            NOT SET
ansi_null_dflt_on       SET            SET
ansi_warnings           SET            SET
ansi_padding            SET            SET
ansi_nulls              SET            SET
concat_null_yields_null SET            SET
isolation level         read committed read committed

textsize と arithabort だけが異なります。

クエリの実行時間にこのような違いがある理由と、その違いを狭めるためにできることはありますか?

特にスキーマを含めるには多すぎるため、クエリを含めることがどれほど役立つかはわかりません。とにかく、ここにあります:

INSERT INTO GeocacherPoints
            (CacherID,
             RegionID,
             Board,
             Control,
             Points)
SELECT z.CacherID,
       z.RegionID,
       z.Board,
       21,
       z.Points
FROM   (SELECT CacherID,
               gp.RegionID,
               Board=gp.Board + 10,
               ( CASE
                   WHEN (SELECT COUNT(*)
                         FROM   Geocache g
                                JOIN GeocacheRegions r
                                  ON ( r.CacheID = g.ID )
                         WHERE  r.RegionID = gp.RegionID
                                AND g.FinderPoints >= 5) < 20 THEN NULL
                   ELSE (SELECT SUM(y.FinderPoints) / 20
                         FROM   (SELECT x.FinderPoints,
                                        ROW_NUMBER() OVER (ORDER BY x.FinderPoints DESC, x.ID) AS Row
                                 FROM   (SELECT g.FinderPoints,
                                                g.ID
                                         FROM   Geocache g
                                                JOIN Log l
                                                  ON ( l.CacheID = g.ID )
                                                JOIN Geocacher c
                                                  ON ( c.ID = l.CacherID )
                                                JOIN GeocacheRegions r
                                                  ON ( r.CacheID = g.ID )
                                         WHERE  YEAR(l.LogDate) = @Year
                                                AND g.FinderPoints >= 5
                                                AND c.ID = gp.CacherID
                                                AND r.RegionID = gp.RegionID) x) y
                         WHERE  y.Row <= 20)
                 END ) Points
        FROM   GeocacherPoints gp
               JOIN Region r
                 ON r.RegionID = gp.RegionID
        WHERE  gp.Control = 21
               AND r.RegionType IN ( 'All', 'State' )
               AND gp.Board = @Board - 10) z
WHERE  z.Points IS NOT NULL
       AND z.Points >= 1 
4

3 に答える 3

7

ARITHABORT原因と誤診されることが多い。

実際、バージョン 2005 以降、ANSI_WARNINGSオンの場合 (両方の接続にあるため)ARITHABORTはとにかく暗黙的にオンになっており、この設定は実際には効果がありません。

ただし、副作用があります。がプラン キャッシュ キーの 1 つとして使用されるANSI_WARNINGSの設定がオフになっている場合に備えて、この設定が異なるセッションは互いのプランを共有できません。ARITHABORT

アプリケーション用にキャッシュされた実行プランは、SSMS でクエリを実行するときに再利用できません。ただし、両方が同じプラン キャッシュ キーを持っているため、現在テスト中のパラメーター値を "盗聴" する新しいプランがコンパイルされます。アプリケーションの計画は、さまざまなパラメーター値に対してコンパイルされている可能性があります。この問題は、「パラメータ スニッフィング」として知られています。

次のようなもので両方の実行計画を取得して比較できます

SELECT usecounts, cacheobjtype, objtype, text, query_plan, value as set_options
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) 
cross APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa
where text like '%INSERT INTO GeocacherPoints (CacherID,RegionID,Board,Control,Points)%' 
and attribute='set_options' and text not like '%this query%'

XML のパラメーター セクションは、パラメーターのコンパイル時の値を示します。

アプリケーションでは遅い、SSMS では速い詳細については、パフォーマンスの謎を理解してください。

実行計画

実際の実行プランではなく推定実行プランを提供しましたが、最初のクエリ プランのみがパラメーター化されており、次の値でコンパイルされていることがわかります。

        <ParameterList>
          <ColumnReference Column="@Dec31" ParameterCompiledValue="'2013-12-31'" />
          <ColumnReference Column="@Jan1" ParameterCompiledValue="'2013-01-01'" />
          <ColumnReference Column="@Board" ParameterCompiledValue="(71)" />
        </ParameterList>

2 番目の実行計画では、パラメーターではなく変数を使用します。それは物事を大きく変えます。

DECLARE @Board INT
DECLARE @Jan1 DATE
DECLARE @Dec31 DATE

SET @Board=71
SET @Jan1='January 1, 2013'
SET @Dec31='December 31, 2013'

INSERT INTO GeocacherPoints

SQL Server は、変数の特定の値をスニッフィングせず、OPTIMIZE FOR UNKNOWNヒントを使用するのと同様の一般的なプランを生成します。その計画の推定行数は、最初の計画よりもはるかに多くなります。

どちらが速いプランでどちらが遅いプランかは述べていません。変数を使用する方が速い場合は、統計を更新する必要がある可能性が高く、ここで説明する問題が発生する可能性があります。統計、行の見積もり、およびパラメーターを使用する方が速い場合、昇順の日付列で、変数のスニッフィングを実行して取得できます。OPTION (RECOMPILE)ヒントを使用して実際の変数値を考慮します。

于 2013-01-03T22:28:26.243 に答える
4

SqlCommand を使用していて、CommandTimeoutの値を指定しない場合、30 秒後に自動的にタイムアウトになります。

于 2013-01-03T19:19:14.590 に答える
-1

この質問は定期的に発生するようです。このリンクはリストの一番上にありました。 クエリはWebアプリからタイムアウトしますが、ManagementStudioからは正常に実行されますARITHABORT間違いなく犯人のようです。

于 2013-01-03T20:34:51.460 に答える