web-dev-qa-db-ja.com

SQL Server 2017:インターリーブ実行はどのように機能しますか?

Interleaved Executionは、2017年のクエリプロセッサの 機能のファミリ の一部であり、以下で構成されています。

では、インターリーブ実行はどのように機能するのでしょうか。

4
Erik Darling

悪魔はテーブル変数にあります

インターリーブ実行は、マルチステートメントテーブル値関数で誤推定された正しいカーディナリティを目的としています。

SQL Serverの以前のバージョンでは、これらの関数は常にお粗末な見積もりを作成していました。

  • 2014、2016:100行
  • 2005-2012:1行

言うまでもなく、これは他のテーブルに結合するときに多くの問題を引き起こす可能性があります。

テーブル変数からデータを選択しても、それ自体で並列処理が妨げられることはありませんが、行推定値が低いと、クエリのコストが低くなり、並列処理が考慮されません。

Interleaved Executionを使用すると、カーディナリティの推定が一時停止され、MSTVFのサブツリーが実行され、より正確なカーディナリティの推定で最適化が再開されます。

MSTVFがインターリーブされた実行を受信するかどうかを知る方法

アダプティブ結合と同様に、インターリーブ実行はクエリプランに記述されます。アダプティブ結合とは異なり、少なくともこの記事の執筆時点では、推定計画には記載されていません。

Interleaved Executionを使用したMSTVFのプラン形状は、MSTVFが含まれている一般的なプランとは少し異なります。

プランの上部にテーブル値関数演算子と、TVFオペレーターが通常はグラフィカルプランにあるテーブル変数のスキャンが表示されます。

NUTS

TVF演算子の上にカーソルを合わせると、属性IsInterleavedExecutedがTrueに設定されていることと、現実をほとんど反映していると推定される行数が表示されます。フラー。

インターリーブ実行が発生しない場合にトラブルシューティングする拡張イベントはありますか?

はい、たくさんあります:

NUTS

これらの一部はデバッグチャネルにあり、拡張するイベントを検索するときにデフォルトで選択されていないことに注意してください。

インターリーブされたExectionにはColumnStoreインデックスが必要ですか?

いいえ、どちらの方法でも機能します。次に例を示します。

SELECT u.Id, mj.*
FROM   dbo.Users_cx AS u --ColumnStore
JOIN   dbo.MultiStatementTVF_Join(0) AS mj
ON mj.UserId = u.Id
WHERE  u.LastAccessDate >= '2016-12-01';


SELECT u.Id, mj.*
FROM   dbo.Users AS u --RowStore
JOIN   dbo.MultiStatementTVF_Join(0) AS mj
ON mj.UserId = u.Id
WHERE  u.LastAccessDate >= '2016-12-01';

これらのクエリはそれぞれ異なるテーブルに結合します。 1つのColumnStore、1つではありません。どちらもInterleaved Executionプランを取得します。

NUTS

インターリーブ実行はいつ機能しますか?

現在、MSTVFで機能するのは、関数の外部で相関が行われる場合のみです。

次に例をいくつか示します。

この関数には内部相関がありません。つまり、テーブルの列と渡された変数に基づいたWHERE句はありません。

CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_Join
(
    @h BIGINT
)
RETURNS @Out TABLE
(
    UserId INT,
    BadgeCount BIGINT
)
AS
    BEGIN
        INSERT INTO @Out ( UserId, BadgeCount )
        SELECT   b.UserId, COUNT_BIG(*) AS BadgeCount
        FROM     dbo.Badges AS b
        GROUP BY b.UserId
        HAVING   COUNT_BIG(*) > @h;
        RETURN;
    END;
GO

この関数は逆であり、変数で渡されるUserId列に述語があります。

CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_CrossApply
(
    @h BIGINT,
    @id INT
)
RETURNS @Out TABLE
(
    UserId INT,
    BadgeCount BIGINT
)
AS
    BEGIN
        INSERT INTO @Out ( UserId, BadgeCount )
        SELECT   b.UserId, COUNT_BIG(*) AS BadgeCount
        FROM     dbo.Badges AS b
        WHERE    b.UserId = @id
        GROUP BY b.UserId
        HAVING   COUNT_BIG(*) > @h;
        RETURN;
    END;
GO

CROSS APPLYが機能しないのはよくある誤解です。実際の制限については、前述のとおりです。内部関数の相関は取引のブレーカーです。

SELECT u.Id, mj.*
FROM   dbo.Users AS u --RowStore
CROSS APPLY dbo.MultiStatementTVF_Join(0) AS mj
WHERE  mj.UserId = u.Id
       AND u.LastAccessDate >= '2016-12-01';


SELECT   TOP 1 u.Id, mj.*
FROM     dbo.Users AS u --RowStore
CROSS APPLY dbo.MultiStatementTVF_CrossApply(2147483647, u.Id) AS mj
WHERE    u.LastAccessDate >= '2016-12-01'
ORDER BY u.Id;

NUTS

6
Erik Darling