最初のクエリの一部は次のとおりです。
FROM [dbo].[calendar] a
LEFT JOIN [dbo].[colleagueList] b
ON b.[Date] = a.d
WHERE DAY(a.[d]) = 1
AND a.[d] BETWEEN @dateStart AND COALESCE(@dateEnd,@dateStart)
計画のそのセクションを以下に示します
修正されたクエリにBETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
は、同じ結合に対してこれがあります
違いはISNULL
さらに単純化され、その結果、次の結合に入るより正確なカーディナリティ統計が得られるようです。これはインラインテーブル値関数であり、リテラル値を使用して呼び出すため、次のようなことができます。
a.[d] BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
a.[d] BETWEEN '2013-06-01' AND ISNULL(NULL,'2013-06-01')
a.[d] BETWEEN '2013-06-01' AND '2013-06-01'
a.[d] = '2013-06-01'
またb.[Date] = a.d
、等価結合述語があるため、プランには等価述語も表示されますb.[Date] = '2013-06-01'
。その結果、28,393
行のカーディナリティの見積もりはかなり正確になる可能性があります。
以下のためのCASE
/のCOALESCE
バージョンとき@dateStart
と@dateEnd
同じ値が、それは同じ等価式にOKを簡素化し、同じ計画を与えますが、時にしている@dateStart = '2013-06-01'
と@dateEnd IS NULL
それだけで限りとなります
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
これは、の暗黙の述語としても適用されColleagueList
ます。今回の推定行数は79.8
rowsです。
次の参加は
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
3,249,590
(やはり)有用なインデックスのないヒープである行テーブルです。
この見積もりの不一致は、使用される結合の選択に影響します。ISNULL
計画では、ハッシュは一度だけテーブルをスキャンするジョイン選択します。COALESCE
計画では、それはまだ一度だけのテーブルをスキャンし、78回の結果をスプールし、それを再生することができるようにする必要がありますことを、ネストされたループ結合を選択したと推定します。つまり、相関するパラメータは変化しないと推定されます。
ネストされたループの計画が2時間後も続いているという事実から、単一のスキャンに対するこの仮定はcolleagueTime
非常に不正確である可能性があります。
2つの結合の間の推定行数がはるかに少ない理由については、テーブルの統計を確認できない限りわかりません。私がテストで見積もった行数をスキューさせた唯一の方法は、NULL
行の負荷を追加することでした(これにより、返された実際の行数は同じままであったとしても、見積もられた行数が減少しました)。
COALESCE
テストデータを含む計画の推定行数は、
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
またはSQLで
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
しかし、これは、列にNULL
値がないというコメントと一致しません。