8

この条件はサージ可能ですか?

AND  DATEDIFF(month,p.PlayerStatusLastTransitionDate,@now) BETWEEN 1 AND 7)

私の経験則では、左側の関数は条件をサージ不可にするというものです..しかし、いくつかの場所で、BETWEEN句がサージ可能であると読んだことがあります。 それで、誰かが確かに知っていますか?

参考のため:

注: 教祖がここで終わっている場合は、Sargable ウィキペディアのページを更新してください。少し更新しましたが、もっと改善できると確信しています:)

4

2 に答える 2

24

AdventureWorks を使用して、次の 2 つの同等のクエリを見ると、次のようになります。

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE DATEDIFF(month,OrderDate,GETDATE()) BETWEEN 1 AND 7;

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE OrderDate >= DATEADD(MONTH, -7, GETDATE())
  AND OrderDate <= DATEADD(MONTH, -1, GETDATE());

どちらの場合も、クラスター化インデックス スキャンが表示されます。

ここに画像の説明を入力

ただし、後者のクエリでのみ推奨/不足しているインデックスに注意してください。

ここに画像の説明を入力

OrderDate 列にインデックスを追加した場合は、クエリを再度実行します。

CREATE INDEX dt ON Sales.SalesOrderHeader(OrderDate);
GO

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE DATEDIFF(month,OrderDate,GETDATE()) BETWEEN 1 AND 7;

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE OrderDate >= DATEADD(MONTH, -7, GETDATE())
  AND OrderDate <= DATEADD(MONTH, -1, GETDATE());

多くの違いが見られます - 後者はシークを使用します:

ここに画像の説明を入力

ここに画像の説明を入力

お使いのバージョンのクエリの推定値がどのようにずれているかも注目してください。これは、大規模なデータ セットでは絶対に悲惨な結果になる可能性があります。

列に適用される関数またはその他の式がサージ可能になるケースはほとんどありません。私が知っている 1 つのケースはCONVERT(DATE, datetime_column)- しかし、その特定の最適化は文書化されていません。列に対して関数/式を使用しても問題ないことを暗黙のうちに示唆しているという理由だけでなく (他のすべてのシナリオではそうではありません)、無駄な読み取りや悲惨な見積もりにつながる可能性があるためです。

于 2012-06-01T16:24:58.873 に答える
8

それがサーガブルだったとしたら、私は非常に驚くでしょう。1つのオプションは、次のように書き直すことです。

WHERE p.PlayerStatusLastTransitionDate >= DATEADD(month,1,CAST(@now AS DATE))
AND   p.PlayerStatusLastTransitionDate <= DATEADD(month,7,CAST(@now AS DATE))

これはサーガブルになると思います (それほどきれいではありませんが)。

于 2012-06-01T16:19:56.673 に答える