ハロウィーンの保護を超えた機能をスケジュールすることには何か利点がありますか


52

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

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

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

回答:


78

はい。

指定に失敗するWITH SCHEMABINDINGと、SQL Serverは関数本体に対して通常行う詳細なチェックをスキップします。関数にデータへのアクセスとしてマークするだけです(質問のリンクに記載されています)。

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

5つの重要な関数プロパティがあります。

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

たとえば、次の非バインドスカラー関数を使用します。

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);

結果

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

これには、予想されるもの以外の意味があります(たとえば、インデックス付きビューまたはインデックス付き計算列での使用)。

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

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

たとえば、次の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へのシークを特徴としています。

プランを探す

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

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;

現在、実行計画はスキャンを備えており、フィルターにスタックした関数を含む述部があります。

スキャン計画

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

エラーメッセージ

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

シークを生成するには、フィルターの述語をプランの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;

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

新しいプロパティ

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


関数でCASTto を使用し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関数のプロパティ

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