7

仕事で新しいクエリを開発しているときに、SQL Query Analyzer でそれを書き、プロファイリングしました。クエリは、テーブル スキャンがなくても非常に優れたパフォーマンスを発揮しましたが、ストアド プロシージャ内にカプセル化したときのパフォーマンスはひどいものでした。実行計画を見ると、SQL Server が TableB のインデックス シークの代わりにテーブル スキャンを使用する別の計画を選択したことがわかりました (テーブルと列の名前を少し難読化する必要がありましたが、クエリ ロジックはまったくわかりませんでした)。変更されました)。

ここにクエリがあります

SELECT     
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount
FROM
    TableA
    INNER JOIN TableB ON TableA.BID = TableB.ID
WHERE     
    (TableA.ShopId = @ShopId)
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created)
ORDER BY 
    DATEPART(hh, TableA.Created)

クエリ「raw」を実行すると、次のトレース統計が得られます

イベント クラス 期間 CPU 読み取り 書き込み
SQL:StmtCompleted 75 41 7 0

そして、次のコマンドを使用してクエリをストアド プロシージャとして実行すると、

DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId

次のトレース統計を取得します

イベント クラス 期間 CPU 読み取り 書き込み
SQL:StmtCompleted 222 10 48 0

クエリを nvarchar に格納し、このように sp_executesql を使用して実行すると、同じ結果が得られます (sproc のように実行されます)。

DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL

ストアド プロシージャには、上記の select ステートメント以外は何も含まれていません。ステートメントがストアド プロシージャとして実行されるという理由だけで、SQL Server が下位の実行プランを選択する原因は何ですか?

現在、 SQL Server 2000で実行しています

4

2 に答える 2

15

これは通常、パラメータスニッフィングと関係があります。対処するのは非常にイライラすることがあります。ストアドプロシージャを再コンパイルすることで解決できる場合もあれば、次のようにストアドプロシージャ内で重複変数を使用する場合もあります。

alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;

次に、クエリで@p1_copyを使用します。ばかげているようですが、動作します。

同じトピックに関する私の最近の質問を確認してください:

SqlServerオプティマイザーがパラメーターと混同されるのはなぜですか?

于 2009-01-07T17:53:09.180 に答える