web-dev-qa-db-ja.com

多くの場所でGETDATE()を使用する場合、変数を使用する方が良いですか?

より良いことには、それはパフォーマンスを限界ではない量だけ改善するということですか?

つまり、GETDATE()を呼び出すたびに、サーバーはその値を返すためにworkをどのくらい実行しますか?

ストアドプロシージャの多くの場所でGETDATE()を使用している場合、トランザクションの日付を格納する変数を作成する必要がありますか?

declare @transDate datetime = GETDATE()

ベンチマークデータは素晴らしいでしょう。

[〜#〜] edit [〜#〜]明確にしたい:私は主に、これら2つの可能性の実際のパフォーマンスの違いと、それが重要かどうかに興味があります。

38
Shmiddty

[注:この回答に反対票を投じる場合は、理由を説明するコメントを残してください。それはすでに何度も反対投票されており、最後にypercube(ありがとう)が少なくとも1つの理由を説明しました。回答は承認されているため削除できません。改善のためにご協力ください。]

Microsoftでのこの交換によると、 GETDATE()は、クエリ内での定数からSQL Server 2005では非決定論的なものに切り替えられました 。振り返ってみると、それは正確ではないと思います。 SQL Server 2005より前は完全に非決定的だったと思いますが、SQL Server 2005以降は「非決定的ランタイム定数」と呼ばれるものにハッキングされました。

(そしてGETDATE()は、修飾子なしで、明確かつ誇らしげに非決定的として定義されます。)

悲しいかな、SQL Serverでは、非決定論は、関数がすべての行に対して評価されることを意味しません。 SQL Serverは、この件に関するドキュメントがほとんどないため、これを不必要に複雑で曖昧にします。

実際には、関数の呼び出しは、クエリのコンパイル時ではなくクエリの実行時に評価され、呼び出されるたびにその値が変化します。実際には、GETDATE()コンパイル時ではなく実行時に使用される式ごとに1回だけ評価されます。ただし、MicrosoftはRand()getdate()を、非決定的ランタイム定数関数と呼ばれる特別なカテゴリに分類しています。対照的に、Postgresはそのようなフープをジャンプせず、「安定した」ものとして実行されたときに定数値を持つ関数を呼び出すだけです。

マーティン・スミスのコメントにもかかわらず、SQL Serverのドキュメントはこの問題について単純に明示されていません-GETDATE()は「非決定的」および「非決定的ランタイム定数」の両方として説明されていますが、その用語は実際には説明されていません。 私が用語を見つけた1つの場所 たとえば、ドキュメントの次の行は、サブクエリで非決定的関数を使用しないことを示しています。それは「非決定論的な実行時定数」に対するばかげたアドバイスになるでしょう。

クエリ内でも定数を持つ変数を使用することをお勧めします。これにより、一貫した値が得られます。これにより、意図が非常に明確になります。クエリ内に単一の値が必要です。 1つのクエリ内で、次のようなことができます。

select . . . 
from (select getdate() as now) params cross join
     . . . 

実際、これはshouldがクエリで1回だけ評価されるという提案ですが、例外がある場合もあります。 getdate()がすべての異なる行で同じ値を返すため、混乱が生じますが、異なる列で異なる値が返される可能性があります。 getdate()を含む各式は独立して評価されます。これを実行すると明らかです:

select Rand(), Rand()
from (values (1), (2), (3)) v(x);

ストアドプロシージャ内では、変数に単一の値を設定します。深夜過ぎにストアドプロシージャが実行され、日付が変更された場合はどうなりますか?結果にどのような影響がありますか?

パフォーマンスに関しては、私の推測では、日付/時刻のルックアップは最小限であり、クエリの実行が開始されると、クエリごとに式ごとに1回発生します。これは実際にはパフォーマンスの問題ではなく、コードの一貫性の問題です。

20
Gordon Linoff

私の提案は、主に変数を使用することです。これは、実行時間の長いプロセスがある場合、GetDate()の値が呼び出し間で異なる可能性があるためです。

GetDate()Date部分のみを使用している場合を除いて、常に同じ値を使用していることを確認できます。

18
Taryn

Getdate()またはsuser_sname()のような関数で変数を使用する理由の1つは、行を挿入する場合、またはGROUP BYを実行する場合のパフォーマンスの大きな違いです。大量の行を挿入すると、これに気づくでしょう。

私自身、300GBのデータをいくつかのテーブルに移行するのに苦労しました。

3
MarianoC

SP内の変数としてGETDATE()関数を使用していくつかのストアドプロシージャをテストしていましたが、IOの読み取りと実行時間が増加していましたクエリオプティマイザーは操作する値が何であるかわからないため、これを読んでください パラメーター、変数、およびリテラルを含むストアドプロシージャの実行 で、すべての単一の部分でGETDATE()関数を使用できますSP as @ Gordon Linoff の値は、実行中に変更されない、または値が変更される可能性があるという考えを回避/削除するために言及しましたパラメータを作成しましたこちらです:

CREATE PROC TestGetdate
(
@CurrentDate DATETIME = NULL
)
AS
SET CurrentDate  = GETDATE()

.....次に、必要に応じてパラメーターを使用すると、良い結果が得られます

コメントや提案は大歓迎です。

2
jthalliens

使った

WHERE ActualDateShipped+30 > dbo.Today()

以下の機能と組み合わせて。クエリ時間が13秒から2秒になりました。この投稿の以前の回答では、SQL 2008/R2のこの問題を解決できませんでした。

CREATE FUNCTION [dbo].[Today]()

    RETURNS date
    AS
    BEGIN

        DECLARE @today date = getdate()

        RETURN @today
    End
0
pghcpa