6


1

SQLステートメントでDATEDIFFを使用しています。 私はそれを選択しています、そしてそれをWHERE句でも使用する必要があります。 この文は機能しません…​

MyTableからInitialSaveとしてDATEDIFF(ss、BegTime、EndTime)を選択しますWHERE InitialSave <= 10

_無効な列名 "InitialSave" _というメッセージが表示されます。

しかし、この文はうまく機能します…​

MyTableからのInitialSaveとしてのDATEDIFF(ss、BegTime、EndTime)の選択DATEDIFF(ss、BegTime、EndTime)<= 10

私のプログラマーは、これは非効率的だと言っています(私はこの関数を2回呼び出しているようです)。

2つの質問です。 最初のステートメントが機能しないのはなぜですか? 2番目のステートメントを使用してそれを行うのは非効率的ですか?

5 Answer


7


*注:*私が最初にこの答えを書いたとき、私は1列のインデックスが他の答えよりも良いパフォーマンスを示すクエリを作成できると言いました(そしてDan Fullerのものを言いました)。 しかし、私は100%正しく考えていませんでした。 実際のところ、計算列または索引付き(マテリアライズド)ビューがないと、比較対象の2つの日付列は_same_表からのものであるため、全表スキャンは_required_になります。

以下の情報にはまだ価値があると思います。すなわち、1)異なるテーブルの列を比較した場合のように、正しい状況でパフォーマンスが向上する可能性、および2)ベストプラクティスに従って再編成する習慣を促進する彼らは正しい方向に考えています。

条件を厳しくする

私が参照しているベストプラクティスは、比較演算子の一方の側に1列に移動することです。

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'

私が言ったように、これは単一のテーブルに対するスキャンを避けません、しかしこのような状況でそれは大きな違いを生むかもしれません:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
   dbo.BeginTime B
   INNER JOIN dbo.EndTime E
      ON B.BeginTime <= E.EndTime
      AND B.BeginTime + '00:00:10' > E.EndTime

`+ EndTime `は、比較の片側だけで両方の条件になりました。 ` BeginTime `テーブルの行数が少なく、 ` EndTime `テーブルのカラム ` EndTime `にインデックスがあるとすると、これは ` DateDiff(second、B.BeginTime、 E.EndTime)+ `。 現在は_sargable_です。これは、有効な「検索引数」があることを意味します。したがって、エンジンは_scans_の `+ BeginTime `テーブルであり、_seek_で ` EndTime `テーブルに入れることができます。 どの列がそれ自体で演算子の片側にあるかを慎重に選択する必要があります-代数を実行して ` AND B.BeginTime> E.EndTime-' 00:00:10 '+ `

  • DateDiffの精度*

また、 `+ DateDiff `は_elapsed_ timeを返さず、代わりに_boundaries_の交差数をカウントすることを指摘する必要があります。 秒を使用した ` DateDiff `の呼び出しが ` 1 `を返す場合、これは `+3 ms +`経過時間を意味するか、または `+1997 ms +`を意味する可能性があります。 これは基本的に-1時間単位の精度です。 +-1/2時間単位の精度を高めるには、「 0+」と「+ EndTime-BegTime +」を比較する次のクエリが必要です。

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

これは、2ではなく合計1秒の最大丸め誤差を持ちます(つまり、floor()操作)。 + datetime +`データ型のみを減算できることに注意してください--- `+ date +`または `+ time +`値を減算するには、 `+ datetime +`に変換するか、他の方法を使用して精度を高めます(a多くの `+ DateAdd +、 `+ DateDiff +`およびその他のジャンク、またはおそらくより高精度の時間単位を使用して分割します)。

この原則は、時間、日、月などのより大きな単位を数えるときに特に重要です。 「1月」の「+ DateDiff +」は、62日間離れている可能性があります(2013年7月1日-2013年8月31日と考えてください)!


5


whereステートメントのselectステートメントで定義された列は、whereが実行されるまでは生成されないため、アクセスできません。

あなたはこれを行うことができます

(SELECT DATEDIFF(ss、BegTime、EndTime)AS InitialSave from MyTable)aTable WHERE InitialSave <= 10からInitialSaveを選択します。

補足として - これは本質的には最初に定義された場所に関してDATEDIFFをwhereステートメントに移動します。 where文の中でカラムに対して関数を使用すると、インデックスが効率的に使用されなくなり、可能であれば避けるべきですが、datediffを使用する必要がある場合は、それを実行する必要があります。


3


それを "機能させる"だけでなく、インデックスを使う必要があります

インデックス付きの計算カラム、またはインデックス付きのビューを使用すると、テーブルスキャンが実行されます。 十分な行数が得られたら、低速スキャンの* PAIN *を感じるでしょう。

計算カラム

ALTER TABLE MyTable ADD ComputedDate AS DATEDIFF(ss、BegTime、EndTime)ON非作成インデックスIX_MyTable_ComputedDate ON MyTable(ComputedDate)にWITH(STATISTICS_NORECOMPUTE = OFF、IGNORE_DUP_KEY = OFF、ALLOW_ROW_LOCKS = ON)[GO]をクリックしてください。

ビューを作成する

YourNewViewをSELECTキー値として、DATEDIFF(ss、BegTime、EndTime)をMyTableから初期設定として作成CREATE_EXEX IX_YourNewViewにYourNewViewを設定(InitialSave)GO


2


あなたは列のエイリアスの代わりに関数を使わなければなりません - それはcount(*)などと同じです。 ピタ。


1


代わりに、 computed columnsを使用することもできます。