オプティマイザーがさまざまな種類のスプールを選択する際に、どのコスト要因が影響しますか?


15

スプールム

SQL Serverには、いくつかの種類のスプールがあります。私が興味を持っている2つはTable SpoolIndexスプール、修正クエリの外です

読み取り専用クエリ、特にネストループ結合の内側では、テーブルスプールまたはインデックススプールのいずれかを使用して、I / Oを削減し、クエリのパフォーマンスを向上させることができます。これらのスプールは、EagerまたはLazyです。あなたと私のように。

私の質問は:

  • どの要素がテーブルとインデックススプールの選択に影響するか
  • イーガースプールとレイジースプールのどちらを選択するか

回答:


12

これは少し広いですが、私は本当の質問を理解しており、それに応じて答えると思います。ただし、テーブルとインデックススプールについてだけ説明します。テーブルスプールとインデックススプールのどちらかを選択するものとして表示するのはまったく正しいとは思いません。ご存知のように、単一のサブツリーで、インデックススプール、テーブルスプール、またはインデックススプールとテーブルスプールの両方を取得することができます。一般的に、次の条件でインデックススプールを取得するのが正しいと考えています。

  1. クエリオプティマイザーには、結合を適用に変換する理由があります
  2. クエリオプティマイザーは実際に適用への変換を実行します
  3. クエリオプティマイザーは、ルールを使用してインデックススプールを追加します(少なくとも、インデックススプールは安全に使用できる必要があります)
  4. インデックススプールのあるプランが選択されています

これらのほとんどは、簡単なデモで見ることができます。一対のヒープを作成することから始めます。

DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;


DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

最初のクエリでは、検索するものは何もありません。

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);

したがって、オプティマイザーが結合を適用に変換する理由はありません。コストがかかるため、テーブルスプールになります。したがって、このクエリは最初のテストに失敗します。

ここに画像の説明を入力してください

次のクエリでは、オプティマイザーに適用を検討する理由があると期待するのは当然です。

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID 
OPTION (LOOP JOIN, MAXDOP 1);

しかし、次のことを意図したものではありません。

ここに画像の説明を入力してください

このクエリは2番目のテストに失敗します。完全な説明はこちらです。最も関連性の高い部分を引用:

オプティマイザーは、適用を可能にするためにその場で索引を作成することを考慮しません。むしろ、イベントのシーケンスは通常逆です。つまり、適切なインデックスが存在するために適用する変換です。

オプティマイザーが適用を検討するように、クエリを書き直すことができます。

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);

しかし、まだインデックススプールはありません。

ここに画像の説明を入力してください

このクエリは3番目のテストに失敗します。SQL Server 2014では、インデックスキーの長さが900バイトに制限されていました。これはSQL Server 2016で拡張されましたが、非クラスター化インデックスのみが対象です。スプールのインデックスはクラスター化インデックスであるため、制限は900バイトのままです。いずれにせよ、クエリの実行中にエラーが発生する可能性があるため、インデックススプールルールは適用できません。

データ型の長さを800に減らすと、プランにインデックススプールが最終的に提供されます。

ここに画像の説明を入力してください

インデックススプールプランは、驚くことではありませんが、スプールのないプランよりも大幅に安くなっています。89.7603単位と598.832単位です。文書化されていないQUERYRULEOFF BuildSpoolクエリヒントとの違いを確認できます。

ここに画像の説明を入力してください

これは完全な答えではありませんが、あなたが探していたものの一部であることを願っています。

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