web-dev-qa-db-ja.com

ハロウィーン保護以外の機能をスキーマバインドすることのメリットはありますか?

SCHEMABINDING関数が更新プランで 不要なスプールを回避する できることはよく知られています。

テーブルに触れない(つまり、データにアクセスしない)単純なT-SQL UDFを使用している場合は、UDFの作成時にSCHEMABINDINGオプションを指定してください。これにより、UDFがスキーマにバインドされ、クエリオプティマイザーがこれらのUDFを含むクエリプランに不要なスプールオペレーターを生成しないようになります。

関数がデータにアクセスしない場合でも、SCHEMABINDING関数のその他の利点はありますか?

53
Paul White 9

はい

WITH SCHEMABINDINGを指定しないと、SQL Serverは、関数本体に対して通常行われる詳細なチェックをスキップします。それは単にデータにアクセスするものとして関数をマークします(質問で与えられたリンクで言及されているように)。

これはパフォーマンスの最適化です。この仮定を行わなかった場合、SQL Serverはすべての関数呼び出しについて詳細なチェックを実行する必要があります(バインドされていない関数はいつでも変更される可能性があるため)。

fiveの重要な関数プロパティがあります:

  • 決定論
  • 精度
  • データアクセス
  • システムデータアクセス
  • システム検証

たとえば、次のバインドされていないスカラー関数を考えます。

CREATE FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
AS
BEGIN
    RETURN '19000101';
END;

メタデータ関数を使用して、5つのプロパティを確認できます。

SELECT 
    IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
    IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
    IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
    UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
    SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);

Result

2つのデータアクセスプロパティはtrueに設定されており、他の3つはfalseに設定されています

これは、予想されるものを超える影響があります(たとえば、インデックス付きビューやインデックス付き計算列で使用)。

クエリオプティマイザーへの影響

Determinismプロパティは、特にクエリオプティマイザーに影響します。実行が許可されている書き換えと操作のタイプに関する詳細なルールがあり、これらは非決定的な要素に対して非常に制限されています。副作用はかなり微妙です。

たとえば、次の2つのテーブルについて考えてみます。

CREATE TABLE dbo.T1
(
    SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
    SomeDate datetime PRIMARY KEY
);

...そして関数を使用するクエリ(前に定義したとおり):

SELECT * 
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = dbo.F(T1.SomeInteger);

クエリプランは予想どおりで、テーブルT2へのシークが特徴です。

Seek plan

ただし、同じ論理クエリが派生テーブルまたは共通テーブル式を使用して記述されている場合:

WITH CTE AS
(
    SELECT *, dt = dbo.F(T1.SomeInteger) 
    FROM dbo.T1 AS T1
)
SELECT * 
FROM CTE
JOIN dbo.T2 AS T2
    ON T2.SomeDate = CTE.dt;

-- Derived table
SELECT
    *
FROM 
(
    SELECT *, dt = dbo.F(T1.SomeInteger)
    FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = T1.dt;

実行計画はスキャンを特徴としており、関数に関係する述語がフィルターでスタックしています。

Scan plan

これは、派生テーブルまたは共通テーブル式がビューまたはインライン関数に置き換えられた場合にも発生します。 FORCESEEKヒント(および他の同様の試み)は成功しません:

Error message

基本的な問題は、クエリオプティマイザーが非決定的なクエリ要素を自由に順序変更できないことです。

シークを生成するには、フィルター述語をプランの下からT2データアクセスに移動する必要があります。関数が非決定的である場合、この動きは防止されます。

修正

この例の修正には、2つのステップが含まれます。

  1. WITH SCHEMABINDINGを追加
  2. 関数を確定的にする

最初のステップは簡単です。 2番目の方法では、文字列からdatetimeへの非決定的な暗黙的キャストを削除します。確定的なCONVERTに置き換えます。 それだけでは十分ではありません

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CONVERT(datetime, '19000101', 112);
END;

関数のプロパティは次のとおりです。

New properties

オプティマイザを解放すると、すべての例で必要なシークプランが生成されます。


関数でCASTからdatetimeを使用しても機能しないことに注意してください。その構文では変換スタイルを指定できないためです。

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CAST('19000101' AS datetime);
END;

この関数定義はスキャン計画を生成し、プロパティはそれが非決定性のままであることを示しています。

CAST function properties

81
Paul White 9