3

オプティマイザーはvarcharパラメーターのnull可能性について混乱しているようで、その理由がわかりません。私はSQLServer2008を使用しています。クエリされるすべての列にインデックスが付けられます。TDate列は、クラスター化されたパーティション索引です。FooValue列はインデックス付きで、null許容でない列です。

例:

CREATE PROCEDURE dbo.MyExample_sp @SDate DATETIME, @EDate DATETIME, @FooValue VARCHAR(50)
AS
SET NOCOUNT ON

--To avoid parameter spoofing / sniffing
DECLARE @sDate1 DATETIME, @eDate1 DATETIME
SET @sDate1 = @sDate
SET @eDate1 = @eDate

SELECT
    fd.Col1,
    fd.Col2,
    fd.TDate,
    fl.FooValue,
    fd.AccountNum
FROM dbo.FooData fd
INNER JOIN dbo.FooLookup fl
    ON fl.FL_ID = fd.FL_ID
WHERE fd.TDate >= @sDate1
    AND fd.TDate < @eDate1
    AND fl.FooValue = @FooValue

これをクエリとして実行すると、期待どおりに機能します。すべてのインデックスはシークであり、なりすましなどはありません。sprocを実行してこれを実行すると、20倍の時間がかかります-同じクエリ-同じパラメータ。ただし、次の変更(最後の行)を行うと、すべてが再び機能します。

CREATE PROCEDURE dbo.MyExample_sp @SDate DATETIME, @EDate DATETIME, @FooValue VARCHAR(50)
AS
SET NOCOUNT ON

--To avoid parameter spoofing / sniffing
DECLARE @sDate1, @eDate1
SET @sDate1 = @sDate
SET @eDate1 = @eDate

SELECT
    fd.Col1,
    fd.Col2,
    fd.TDate,
    fl.FooValue,
    fd.AccountNum
FROM dbo.FooData fd
INNER JOIN dbo.FooLookup fl
    ON fl.FL_ID = fd.FL_ID
WHERE fd.TDate >= @sDate1
    AND fd.TDate < @eDate1
    AND fl.FooValue = ISNULL(@FooValue, 'testthis')

オプティマイザがパラメータがnull許容かどうかについて混乱しているようですか?また、パラメータにデフォルト値を追加しても違いはありません。= isnull(@parameter、'some constant')を使用しない限り、sprocの実行にはまだ永遠にかかります

私はこれを理解できてうれしいです。しかし、なぜこれが起こっているのか、そして問題を解決するためのよりエレガントな方法があったのかどうかを理解したいと思います。

4

1 に答える 1

2

Re:Nullable変数

T-SQLの変数に対してnull許容の概念はありません。これは、?を使用してc#で変数をnull許容として定義できる方法です。ストアドプロシージャにパラメータがある場合、エンドユーザーは、実際の値であれnullであれ、必要なものをストアドプロシージャに渡すことができます。

Re:クエリプラン

キャッシュされるクエリプランは、このストアドプロシージャを初めて呼び出したときに生成されるクエリプランです。したがって、最初に@FooValueを実行したときにnullを渡した場合は、@用に最適化されます。 FooValue=null。

クエリを他の値に最適化するために使用できるOPTIMIZEFORヒントがあります。

または、 WITH RECOMPILEを使用することもできます。これにより、ストアドプロシージャを実行するたびに、クエリプランが強制的に再生成されます。

これらのタイプのヒントを使用する場合は明らかにトレードオフがあるため、使用する前に必ず理解してください。

于 2012-09-06T19:38:04.373 に答える