http://blogs.msdn.com/b/psssql/archive/2010/10/28/query-performance-and-multi-statement-table-valued-functions.aspx およびその他に基づく記事では、SQL Serverは、複数行のテーブル値関数が1行を返すと想定しています。これにより、実際に多くの行が返される場合、呼び出し元のステートメントの実行プランが正しく選択されません。
WITH SCHEMABINDINGをCREATE FUNCTIONのRETURNS句に追加すると、関数の戻り値のカーディナリティがより正確に見積もられますか?
この関数にUserIdを渡して、ユーザーがアクセスを許可されているRecordId値のテーブルを取得し、一部のユーザーは少数のレコードしか表示できず、一部のユーザーは多数またはすべてのレコード、関数または呼び出しステートメント(またはそれらを含むプロシージャ)は、FORCE RECOMPILEを使用することから利益を得ますか?関数でWITH SCHEMABINDINGを使用すると、この答えが変わりますか?
私は実験でこれを理解できることを理解していますが、誰かがすでに答えを理解していることを願っています。これが十分に文書化されている場所へのポインタが役立つでしょう。
私のテストでは、いいえ、WITH SCHEMABINDING
は、カーディナリティーの見積もりを改善しません。私は簡単なテーブルを作成しました:
CREATE TABLE dbo.myobjects(id INT PRIMARY KEY);
INSERT dbo.myobjects SELECT [object_id] FROM sys.all_objects;
次に2つの関数:
CREATE FUNCTION dbo.noschemabinding(@UserID INT)
RETURNS @x TABLE (id INT)
AS
BEGIN
INSERT @x SELECT id FROM dbo.myobjects;
RETURN;
END
GO
CREATE FUNCTION dbo.withschemabinding(@UserID INT)
RETURNS @x TABLE (id INT)
WITH SCHEMABINDING
AS
BEGIN
INSERT @x SELECT id FROM dbo.myobjects;
RETURN;
END
GO
実際のプランを比較すると、どちらも推定行= 1、実際の行= 2112を示しています(この後者の数値は、バージョン/ SPによってはシステムで異なる場合があります)。
速度の比較:
SET NOCOUNT ON;
GO
SELECT SYSDATETIME();
GO
SELECT id INTO #x FROM dbo.noschemabinding(1);
DROP TABLE #x;
GO 1000
GO
SELECT SYSDATETIME();
GO
SELECT id INTO #x FROM dbo.withschemabinding(1);
DROP TABLE #x;
GO 1000
SELECT SYSDATETIME();
結果:
run 1 run 2
---------------- ------------------ ------------------
No schemabinding 14632 milliseconds 14079 milliseconds
Schemabinding 14251 milliseconds 13979 milliseconds
それで、それは重要ですか?いいえ。
この場合のSCHEMABINDING
は、基になるスキーマの安定性というより重要な目標に使用されます。関数をインラインTVFに変換する方が、複数ステートメントのTVFでプランに影響するあいまいな違いを追跡するよりも、最適化の機会がはるかに多くなります。
どうやらSQL Server 2017では、データベースで互換性レベル140を使用している限り、 Interleaved Execution を使用してmsTVFの推定が改善されたようです。