TIISNULL()
は遅延関数ですか?
つまり、次のようなコードを記述した場合:
SELECT ISNULL(MYFIELD, getMyFunction()) FROM MYTABLE
それは常に評価されますか、それとも実際にnullgetMyFunction()
の場合にのみ評価されますか?MYFIELD
TIISNULL()
は遅延関数ですか?
つまり、次のようなコードを記述した場合:
SELECT ISNULL(MYFIELD, getMyFunction()) FROM MYTABLE
それは常に評価されますか、それとも実際にnullgetMyFunction()
の場合にのみ評価されますか?MYFIELD
これはうまくいきます
declare @X int
set @X = 1
select isnull(@X, 1/0)
しかし、集計を導入すると失敗し、2 番目の引数が最初の引数の前に評価される可能性があることが証明されます。
declare @X int
set @X = 1
select isnull(@X, min(1/0))
あなたが参照しているこの「怠惰な」機能は、実際には「短絡」と呼ばれ、
特に ISNULL 式に udf がある場合は常に機能するとは限りません。
それを証明するためにテストが実行されたこの記事を確認してください:
Short-circuiting (主に VB.Net および SQL Server)
T-SQL は宣言型言語であるため、結果を取得するために使用されるアルゴリズムを制御できません。必要な結果を宣言するだけです。費用対効果の高い計画を把握するのは、クエリ エンジン/オプティマイザー次第です。また、SQL Server では、オプティマイザーは「矛盾検出」を使用します。これは、手続き型言語で想定されるような左から右への評価を保証するものではありません。
あなたの例では、簡単なテストを行いました:
スカラー値のUDFを作成してゼロ除算エラーを呼び出しました:
CREATE FUNCTION getMyFunction
( @MyValue INT )
RETURNS INT
AS
BEGIN
RETURN (1/0)
END
GO
Divide by zero error encountered
以下のクエリを実行してもエラーは発生しませんでした。
DECLARE @test INT
SET @test = 1
SET @test = ISNULL(@test, (dbo.getMyFunction(1)))
SELECT @test
SET
以下のステートメントに変更すると、Divide by zero error encountered.
エラーが発生しました。SELECT
(で導入ISNULL
)
SET @test = ISNULL(@test, (SELECT dbo.getMyFunction(1)))
しかし、変数の代わりに値を使用すると、エラーは発生しませんでした。
SELECT ISNULL(1, (dbo.getMyFunction(1)))
SELECT ISNULL(1, (SELECT dbo.getMyFunction(1)))
したがって、オプティマイザーがすべての順列に対してこれらの式をどのように評価しているかを実際に理解していない限り、T-SQL の短絡機能に依存しない方が安全です。
それは、最もうまくいくと思う方です。
今は機能的に怠け者です。これは重要なことです。たとえば、col1
がnull のvarchar
ときに常に数値を含む の場合、col2
isnull(col2, cast(col1 as int))
動作します。
ただし、null チェックの前または同時にキャストを試行し、nullcol2
でない場合はエラーを処理するか、null の場合のみキャストを試行するかは指定されていませんcol2
。
少なくとも、col1
テーブルを 1 回スキャンして 2 つの値を取得する方が、2 回スキャンしてそれぞれ 1 つの値を取得するよりも高速になるため、どのような場合でも取得できると予想されます。
同じ SQL コマンドを非常に異なる方法で実行できます。これは、テーブルに関するインデックスと統計の知識に基づいて、与えられた命令が低レベルの操作に変換されるためです。
そのため、パフォーマンスに関しては、「それが良いと思われる場合はそうであり、そうでない場合はそうではない」というのが答えです。
観察された動作に関しては、怠け者です。
編集: Mikael Eriksson's answer は、怠け者ではないために実際にエラーが発生する場合があることを示しています。パフォーマンスへの影響に関しては、ここで私の回答に固執しますが、少なくともいくつかのケースでの正確性の影響に関しては、彼は不可欠です。
の挙動の違いから判断すると
SELECT ISNULL(1, 1/0)
SELECT ISNULL(NULL, 1/0)
最初の SELECT は 1 を返し、2 番目はMsg 8134, Level 16, State 1, Line 4
Divide by zero error encountered.
エラーを発生させます。