仕事で新しいクエリを開発しているときに、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で実行しています