これら2つのクエリは論理的に同等ですか?


10

これら2つのクエリは論理的に同等ですか?

DECLARE @DateTime DATETIME = GETDATE()

クエリ1

SELECT *
FROM   MyTable
WHERE  Datediff(DAY, LogInsertTime, @DateTime) > 7   

クエリ2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

それらが論理的に同等でない場合、WHERE句がインデックスを効果的に使用できるように(つまり、関数のラッピングを排除する)ために、最初のクエリと論理的に同等のものを提供できますか?


タイプLogInsertTimeは何ですか?
dezso 2012年


LogInsertTimeはDATETIMEです
Alf47 '17 / 10/17

回答:


15

投稿した2つのクエリが論理的に同等かどうかは関係ありません。どちらも使用しないでください。私はあなたをいくつかのものから遠ざけるようにします:

  1. 可能な限り、列に関数を適用しないようにしてください。列ではなく定数に対してこれらの計算を維持することは常に優れており、ほとんどの場合より優れています。これにより、SARGabilityが破壊され、それらの列のインデックスが役に立たなくなります。この場合、特にLogDateTimeインデックスが付けられている(またはインデックス付けされる可能性がある)場合は、クエリ2を優先します。
  2. 簡単な日付の計算は好きではないので、お勧めしません。確かに、入力の方が高速ですが、DATEデータ型で試してみると、醜いエラーが発生します。たとえば、次のように説明する方がはるかに適切です。

    WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime);

同意しますが、私の目標は、クエリ1をクエリ2のようなものに変更して、インデックスを効果的に使用できるようにすることでした。あなたの助けをありがとう
Alf47

8

次のsargeableクエリを使用します。

SELECT * FROM MyTable WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime)

理由:@ DateTime-7の結果は文書化されていないと思います。それがたまたまDATEADD(DAY、-7、@DateTime)と同等であるとしても、それ以降のリリースでは壊れる可能性があります。


それはまさに私が探していたものです。ありがとう
Alf47

2
実際には、文書化され、明確に定義されています- (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.。それでも、明示的な日付関数を使用すると、結果のクエリが「算術演算子マジック」よりも読みやすく、保守しやすくなることに同意します。
ハインツィ

6

それらは同等ではありません。7日前で現在の時刻より前のレコード -クエリ#2でのみ返されます。

使用日数を比較するとDATEADD機能をそれが考慮時間の一部を取ることはありません。時間に関係なく、日曜日と月曜日を比較すると、関数は1を返します。

デモ:

DECLARE @MyTable TABLE(pk INT, LogInsertTime DATETIME);

INSERT @MyTable
VALUES (1, DATEADD(HOUR, 1, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE))AS DATETIME))),
(2, DATEADD(HOUR, 23, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE)) AS DATETIME)));

DECLARE @DateTime DATETIME = GETDATE();

SELECT *
FROM @MyTable
WHERE DATEDIFF(DAY, LogInsertTime, @DateTime) > 7;

-- 0 records.

SELECT *
FROM @MyTable
WHERE LogInsertTime < @DateTime - 7;
-- 1 record.

潜在的なインデックスの使用を可能にする最初のクエリの論理的な同等物は、時刻の部分を削除するか@DateTime、時刻を0:00:00次のように設定することです:

SELECT *
FROM @MyTable
WHERE LogInsertTime < CAST(@DateTime - 7 AS DATE);

最初のクエリでインデックスを使用できないのLogInsertTimeは、列が関数内に埋め込まれているためです。クエリ#2は、列を定数値と比較して、オプティマイザがのインデックスを選択できるようにしますLogInsertTime

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.