クエリ実行演算子

はじめに

このページでは、Cloud Spanner のクエリ実行プランで使用する演算子について詳しく説明します。Cloud Console を使用して特定のクエリの実行プランを取得する方法については、Cloud Spanner によるクエリの実行方法を理解するをご覧ください。

このページのクエリと実行プランは、次のデータベース スキーマに基づいています。

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
  BirthDate  DATE,
) PRIMARY KEY(SingerId);
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);

CREATE TABLE Albums (
  SingerId        INT64 NOT NULL,
  AlbumId         INT64 NOT NULL,
  AlbumTitle      STRING(MAX),
  MarketingBudget INT64,
) PRIMARY KEY(SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);

CREATE TABLE Songs (
  SingerId  INT64 NOT NULL,
  AlbumId   INT64 NOT NULL,
  TrackId   INT64 NOT NULL,
  SongName  STRING(MAX),
  Duration  INT64,
  SongGenre STRING(25),
) PRIMARY KEY(SingerId, AlbumId, TrackId),
  INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums;

CREATE INDEX SongsBySongName ON Songs(SongName);

CREATE TABLE Concerts (
  VenueId      INT64 NOT NULL,
  SingerId     INT64 NOT NULL,
  ConcertDate  DATE NOT NULL,
  BeginTime    TIMESTAMP,
  EndTime      TIMESTAMP,
  TicketPrices ARRAY<INT64>,
) PRIMARY KEY(VenueId, SingerId, ConcertDate);

次のデータ操作言語(DML)ステートメントを使用して、これらのテーブルにデータを追加できます。

INSERT INTO Singers (SingerId, FirstName, LastName, BirthDate)
VALUES (1, "Marc", "Richards", "1970-09-03"),
       (2, "Catalina", "Smith", "1990-08-17"),
       (3, "Alice", "Trentor", "1991-10-02"),
       (4, "Lea", "Martin", "1991-11-09"),
       (5, "David", "Lomond", "1977-01-29");

INSERT INTO Albums (SingerId, AlbumId, AlbumTitle)
VALUES (1, 1, "Total Junk"),
       (1, 2, "Go, Go, Go"),
       (2, 1, "Green"),
       (2, 2, "Forever Hold Your Peace"),
       (2, 3, "Terrified"),
       (3, 1, "Nothing To Do With Me"),
       (4, 1, "Play");

INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre)
VALUES (2, 1, 1, "Let's Get Back Together", 182, "COUNTRY"),
       (2, 1, 2, "Starting Again", 156, "ROCK"),
       (2, 1, 3, "I Knew You Were Magic", 294, "BLUES"),
       (2, 1, 4, "42", 185, "CLASSICAL"),
       (2, 1, 5, "Blue", 238, "BLUES"),
       (2, 1, 6, "Nothing Is The Same", 303, "BLUES"),
       (2, 1, 7, "The Second Time", 255, "ROCK"),
       (2, 3, 1, "Fight Story", 194, "ROCK"),
       (3, 1, 1, "Not About The Guitar", 278, "BLUES");

リーフ演算子

リーフ演算子は子のない演算子です。リーフ演算子には次の種類があります。

配列フラット化

配列フラット化演算子は、入力配列を要素の行にフラット化します。各行は、配列の実際の値が入る列と配列内での位置(先頭は 0)が入る列から構成されます。配列内の位置を表す列はない場合もあります。

たとえば、次のクエリについて考えます。

SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;

このクエリは、配列 [1,2,3] の値を列 a にフラット化し、配列内での位置を列 b に示します。

結果は次のようになります。

a b
1 0
2 1
3 2

実行プランは次のとおりです。

配列フラット化演算子

生成関係

生成関係演算子は 0 個以上の行を返します。

単位関係

単位関係は 1 行を返します。これは、生成関係演算子の特殊なケースです。

たとえば、次のクエリについて考えます。

SELECT 1 + 2 AS Result;

結果は次のとおりです。

結果
3

実行プランは次のとおりです。

単位関係演算子

空の関係

空の関係は行を返しません。これは、生成関係演算子の特殊なケースです。

たとえば、次のクエリについて考えます。

SELECT * FROM Albums LIMIT 0

結果は次のとおりです。

No results

実行プランは次のとおりです。

空の関係演算子

スキャン

スキャン演算子は、行の取得元をスキャンして行を返します。スキャン演算子の種類は次のとおりです。

  • テーブル スキャン: テーブルをスキャンします。
  • インデックス スキャン: インデックスをスキャンします。
  • バッチスキャン: 他の関係演算子が作成した中間テーブル(たとえば、分散クロス適用によって作成されたテーブル)をスキャンします。

可能であれば、Cloud Spanner はスキャン中に簡単な述語をキーに適用します。述語を適用すると、テーブルまたはインデックス全体を読み取る必要がなくなるため、スキャンが効率的に実行されます。実行プランで、述語は KeyPredicate: column=value という形式で記述されます。

たとえば、次のクエリについて考えます。

SELECT s.LastName
FROM singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = 'Catalina';

結果は次のようになります。

LastName
Smith

実行プランは次のとおりです。

スキャン演算子

実行プランで、最上位の分散ユニオン演算子がリモート サーバーにサブプランを送信します。各サブプランには、結果のシリアル化演算子とインデックス スキャン演算子が含まれます。述語 Key Predicate: FirstName = 'Catalina' は、スキャンの範囲をインデックス SingersByFirstLastnameFirstNameCatalina の行に限定します。インデックス スキャンの出力が結果のシリアル化演算子に返されます。

単項演算子

単項演算子は、関連する子が 1 つしかない演算子です。

次の演算子が単項演算子になります。

集計

集計演算子は、GROUP BY SQL ステートメントと集計関数(COUNT など)を実装します。集計演算子の入力は論理的に分割され、キー列でグループ化されます。GROUP BY が存在しない場合、単一のグループに配置されます。各グループで、ゼロ個以上の集計が計算されます。

たとえば、次のクエリについて考えます。

SELECT s.SingerId, AVG(s.duration) AS average, COUNT(*) AS count
FROM Songs AS s
GROUP BY SingerId;

このクエリは、SingerId でグループ化し、AVG 集計と COUNT 集計を実行します。

結果は次のようになります。

SingerId average count
3 278 1
2 225.875 8

実行プランは次のとおりです。

集計演算子

集計演算子はストリームベースまたはハッシュベースになります。上の実行プランでは、ストリームベースの集計になっています。ストリームベースの集計は、並べ替え済みの入力(GROUP BY がある場合)から読み取り、ブロック化を行わずにグループを計算します。ハッシュベースの集計は、ハッシュ テーブルを作成し、複数の入力行の増分集計を同時に維持します。ハッシュベースの集計よりもストリームベースの集計のほうが高速で、メモリの使用量も少なくなりますが、キー列またはセカンダリ インデックスのいずれかを使用して入力の並べ替えが必要になります。

分散環境では、集計演算子はローカルとグローバルに分かれます。それぞれのリモート サーバーがローカルで入力行に集計を実行し、結果をルートサーバーに返します。全体の集計はルートサーバーで行います。

ミューテーション適用

ミューテーション適用演算子は、データ操作言語(DML)ステートメントのミューテーションをテーブルに適用します。これは、DML ステートメントのクエリプランの最上位演算子です。

たとえば、次のクエリについて考えます。

DELETE FROM Singers
WHERE FirstName = 'Alice';

結果は次のようになります。

4 rows deleted
This statement deleted 4 rows and did not return any rows.

実行プランは次のとおりです。

ミューテーション適用演算子

バッチ作成

バッチ作成演算子は、入力行を 1 つのシーケンスにまとめます。バッチ作成オペレーションは通常、分散クロス適用の中で行われます。バッチ作成時に入力行の並べ替えが再度実行されます。バッチ演算子の 1 回ので実行で処理される入力行の数は一定ではありません。

実行プランのバッチ作成演算子の例については、分散クロス適用演算子をご覧ください。

コンピューティング

計算演算子は、入力行を読み取り、スカラー式で計算される列を追加して結果を生成します。実行プランでの計算演算子の例については、UNION ALL 演算子をご覧ください。

構造体計算

構造体計算演算子は、入力列のフィールドを含む構造体の変数を作成します。

たとえば、次のクエリについて考えます。

SELECT FirstName,
       ARRAY(SELECT AS STRUCT song.SongName, song.SongGenre
             FROM Songs AS song
             WHERE song.SingerId = singer.SingerId)
FROM singers AS singer
WHERE singer.SingerId = 3;

結果は次のようになります。

FirstName 未設定
Alice [["Not About The Guitar","BLUES"]]

実行プランは次のとおりです。

構造体計算演算子

実行プランでは、配列サブクエリ演算子が分散ユニオン演算子から入力を受信しています。分散ユニオン演算子は、構造体計算演算子から入力を受信しています。構造体計算演算子は、Songs テーブルの SongName 列と SongGenre 列から構造体を作成します。

フィルタ

フィルタ演算子は、入力からすべての行を読み取り、各行にスカラー述語を適用して、述語の条件を満たす行のみを返します。

たとえば、次のクエリについて考えます。

SELECT s.LastName FROM (SELECT s.LastName
FROM Singers AS s LIMIT 3) s
WHERE s.LastName LIKE 'Rich%';

結果は次のようになります。

LastName
Richards

実行プランは次のとおりです。

フィルタ演算子

名前が Rich で始まる歌手を条件とする述語がフィルタとして実装されています。フィルタの入力はインデックス スキャンからの出力です。フィルタの出力は LastNameRich で始まる行です。

フィルタがスキャンのすぐ上にある場合、フィルタによりデータの読み取り方法が変わります。たとえば、キー k を持つテーブルについて考えてみましょう。述語 k = 5 を持つフィルタがテーブル スキャンのすぐ上にあるため、入力全体の読み取りを行わず、k = 5 に一致する行を検索します。このため、クエリの実行効率がよくなります。上の例では、フィルタ演算子は述語 WHERE s.LastName LIKE 'Rich%' を満たす行しか読み取りません。

フィルタ スキャン

フィルタ スキャン演算子は、常にテーブル スキャンまたはインデックス スキャンよりも上位で実行されます。スキャンとの連携により、データベースから読み込まれる行数が少なくなります。結果として、フィルタを使用する場合よりもスキャンが高速になります。Cloud Spanner は特定の条件でフィルタ スキャンを適用します。

  • シーク可能な条件: この条件は、Cloud Spanner がテーブル内でアクセスする行を特定したときに適用されます。これは通常、フィルタが主キーのプレフィックスにある場合に発生します。たとえば、主キーが Col1Col2 で構成されている場合、Col1 または Col1Col2 に明示的な値を含む WHERE 句がシーク可能になります。この場合、Cloud Spanner はキー範囲内のデータのみを読み取ります。
  • 残存条件: Cloud Spanner がスキャン結果を評価し、読み取るデータの量を制限する条件。

たとえば、次のクエリについて考えます。

SELECT LastName
FROM Singers
WHERE SingerId = 1

結果は次のようになります。

LastName
Richards

実行プランは次のとおりです。

フィルタ スキャン演算子

制限

制限演算子は、返される行数を制限します。OFFSET パラメータに開始行を指定します(このパラメータは省略可能です)。分散環境では、制限演算子はローカルとグローバルに分かれます。それぞれのリモート サーバーが出力行にローカルの制限を適用し、結果をルートサーバーに返します。ルートサーバーがリモート サーバーから受信した行を集計し、全体の制限を適用します。

たとえば、次のクエリについて考えます。

SELECT s.SongName
FROM Songs AS s
LIMIT 3;

結果は次のようになります。

SongName
Not About The Guitar
The Second Time
Starting Again

実行プランは次のとおりです。

制限演算子

ローカルの制限は、それぞれのリモート サーバーの制限です。ルートサーバーは、リモート サーバーから受信した行を集計し、全体の制限を適用します。

サンプル

サンプル演算子は、入力行のサンプリングに基づいて入力のサブセットを返します。サポートされているサンプリング方法は BernoulliReservoir です。

たとえば、次のクエリについて考えます。

SELECT s.SongName
FROM Songs AS s TABLESAMPLE BERNOULLI (10 PERCENT);

このクエリでは、Bernoulli サンプリングを使用し、サンプリング レートを 10% に設定しています。

結果は次のようになります。

SongName
Starting Again
Nothing Is The Same

この結果はサンプルで、クエリを実行するたびに変わります。同じクエリを実行しても変わる場合があります。

実行プランは次のとおりです。

サンプル演算子

この実行プランでは、サンプル演算子が分散ユニオン演算子から入力を受信します。分散ユニオン演算子はインデックス スキャンから入力を受信します。サンプル演算子は、サンプル行を結果のシリアル化演算子に返しています。

結果のシリアル化

結果のシリアル化演算子は構造体演算子の特別なケースで、クライアントに返す前にクエリの最終結果の各行をシリアル化します。

たとえば、次のクエリについて考えます。

SELECT ARRAY(SELECT AS STRUCT so.SongName, so.SongGenre
             FROM Songs AS so
             WHERE so.SingerId = s.SingerId)
FROM Singers AS s;

このクエリは、SingerId に基づいて SongNameSongGenre の配列を取得します。

結果は次のようになります。

未設定
[]
[[Let's Get Back Together, COUNTRY], [Starting Again, ROCK]]
[[Not About The Guitar, BLUES]]
[]
[]

実行プランは次のとおりです。

結果のシリアル化演算子

結果のシリアル化演算子は、Songs テーブルの各行に SongNameSongGenre を含む結果を作成します。

並べ替え

並べ替え演算子は、入力行を読み取り、列で並べ替えて結果を返します。

たとえば、次のクエリについて考えます。

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre;

結果は次のようになります。

SongGenre
BLUES
BLUES
BLUES
BLUES
CLASSICAL
COUNTRY
ROCK
ROCK
ROCK

実行プランは次のとおりです。

並べ替え演算子

この実行プランでは、並べ替え演算子は分散ユニオン演算子から入力行を受け取り、入力行を並べ替えてから結果のシリアル化演算子に返します。

返す行数を制限するには、並べ替え演算子に LIMIT パラメータと OFFSET パラメータを指定します。これらのパラメータは省略可能です。分散環境では、LIMIT または OFFSET 演算子を使用した並べ替え演算子はローカルとグローバルに分かれます。それぞれのリモート サーバーが入力行に並べ替え順とローカルの制限 / オフセットを適用し、結果をルートサーバーに返します。ルートサーバーは、リモート サーバーから受信した行を集計して並べ替え、全体の制限 / オフセットを適用します。

たとえば、次のクエリについて考えます。

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre
LIMIT 3;

結果は次のようになります。

SongGenre
BLUES
BLUES
BLUES

実行プランは次のとおりです。

並べ替え演算子と制限

この実行プランは、リモート サーバーのローカル制限とルートサーバーの全体制限を表しています。

ユニオン入力

ユニオン入力演算子は、結果を UNION ALL 演算子に返します。実行プランでのユニオン入力演算子の例については、UNION ALL 演算子を参照してください。

2 項演算子

2 項演算子は、関係する子が 2 つある演算子です。次の演算子が 2 項演算子になります。

クロス適用

クロス適用演算子は、別のテーブルのクエリで取得した各行にテーブルクエリを実行し、テーブルクエリの結果をすべて結合して返します。クロス適用演算子と外部適用演算子は行単位で処理を行いますが、ハッシュ結合などの演算子はセット単位で処理を行います。クロス適用演算子には、入力とマップという 2 つの入力があります。クロス適用演算子は、入力側の各行をマップ側に適用します。クロス適用の結果には、入力側とマップ側の両方の列が含まれます。

たとえば、次のクエリについて考えます。

SELECT si.FirstName,
  (SELECT so.SongName
   FROM Songs AS so
   WHERE so.SingerId=si.SingerId
   LIMIT 1)
FROM Singers AS si;

このクエリは、歌手の名前とその歌手の曲名の 1 つを取得します。

結果は次のようになります。

FirstName 未設定
Alice Not About The Guitar
Catalina Let's Get Back Together
David NULL
Lea NULL
Marc NULL

最初の列は Singers テーブルから取得し、2 番目の列は Songs テーブルから取得しています。SingerIdSingers テーブルに存在していますが、Songs テーブルに該当する SingerId が存在しないため、2 番目の列に NULL が入っています。

実行プランは次のとおりです。

クロス適用演算子

最上位ノードは分散ユニオン演算子です。分散ユニオン演算子は、サブプランをリモート サーバーに分散します。サブプランに含まれている結果のシリアル化演算子が歌手の名前とその歌手の曲名を計算し、出力の各行にまとめて出力します。

結果のシリアル化演算子は、クロス適用演算子から入力を受信します。クロス適用演算子の入力側は Singers テーブルのテーブル スキャンです。

クロス適用演算のマップ側には、次のものが上から順に含まれます。

  • 集計演算子。Songs.SongName を返します。
  • 制限演算子。1 人の歌手につき、返される曲数を 1 に制限しています。
  • SongsBySingerAlbumSongNameDesc インデックスのインデックス スキャン

クロス適用演算子は、入力側のマップとマップ側で SingerId が同じ行を関連付けます。クロス適用演算子の出力は、入力行からの FirstName 値とマップ行からの SongName 値になります。SingerId に一致するマップ行がない場合、SongName 値は NULL になります。実行プランの最上位にある分散ユニオン演算子は、リモート サーバーからの出力行をすべて結合し、クエリ結果として返します。

ハッシュ結合

ハッシュ結合演算子はハッシュベースで行う SQL 結合です。ハッシュ結合はセット単位の処理を実行します。ハッシュ結合演算子は、build とマークされた入力行を読み取り、結合条件に基づいてハッシュ テーブルに挿入します。次に、probe とマークされた行を読み取ります。ハッシュ結合演算子は、プローブ入力から読み取った各行に対して、ハッシュ テーブル内で一致する行を探します。一致した行を結果として返します。

たとえば、次のクエリについて考えます。

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a HASH JOIN Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;

結果は次のようになります。

AlbumTitle SongName
Nothing To Do With Me Not About The Guitar
Green The Second Time
Green Starting Again
Green Nothing Is The Same
Green Let's Get Back Together
Green I Knew You Were Magic
Green Blue
Green 42
Terrified Fight Story

実行プランは次のとおりです。

ハッシュ結合演算子

この実行プランで、ビルドはテーブル Albums に対するスキャンを分散する分散ユニオンです。Probe は、インデックス SongsBySingerAlbumSongNameDesc に対するスキャンを分散する分散ユニオン演算子です。ハッシュ結合演算子がビルド側からすべての行を読み取ります。各ビルド行が、条件 a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId の列に基づいてハッシュ テーブルに配置されます。次に、ハッシュ結合演算子はプローブ側からすべての行を読み取ります。各プローブ行に対して、ハッシュ結合演算子はハッシュ テーブル内で一致する行を探し、一致した結果を返します。

ハッシュ テーブルで一致した結果は、残余条件でフィルタリングされてから返される場合があります(たとえば、非等値結合に残余条件がある場合)。ハッシュ結合の実行プランは、メモリ管理や結合が一定でないため、複雑になる可能性があります。メインのハッシュ結合アルゴリズムが内部結合、半結合、反結合、外部結合の変数処理に使用されます。

外部適用

外部適用演算子はクロス適用演算子に似ていますが、マップ側の実行で必要に応じて行に NULL を埋め込むことによって、少なくとも 1 行を返す点が異なります(左外部結合を行います)。

N 項演算子

N 項演算子は、関連する子が 3 つ以上ある演算子です。次の演算子が N 項演算子になります。

UNION ALL

UNION ALL 演算子は、重複を除外せずに子のすべての行セットを結合します。UNION ALL 演算子は、複数のサーバーに分散するユニオン入力演算子から入力を受信します。UNION ALL 演算子を使用する場合、同じスキーマの入力が必要になります。つまり、各列に同じデータ型のセットが含まれている必要があります。

たとえば、次のクエリについて考えます。

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 4 b
UNION ALL
SELECT 5 a, 6 b;

子の行は 2 つの整数から構成されています。

結果は次のようになります。

a b
1 2
3 4
5 6

実行プランは次のとおりです。

union_all_operator

UNION ALL 演算子は、入力行を結合して結果のシリアル化演算子に結果を送信します。

次のクエリでは、各列のデータに同じデータ型が使用されているため、子の列名で異なる変数を使用していても処理に成功します。

SELECT 1 a, 2 b
UNION ALL
SELECT 3 c, 4 e;

次のクエリでは、子の列で異なるデータ型が使用されているため、処理に失敗します。

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 'This is a string' b;

スカラー サブクエリ

スカラー サブクエリは、スカラー式に含まれる SQL サブ式です。可能であれば、Cloud Spanner はスカラー サブクエリを削除します。実行プランでスカラー サブクエリが明示的に使用されている場合があります。

たとえば、次のクエリについて考えます。

SELECT FirstName,
IF(FirstName='Alice',
   (SELECT COUNT(*)
    FROM Songs
    WHERE Duration > 300),
   0)
FROM Singers;

SQL サブ式は次のようになります。

SELECT COUNT(*)
FROM Songs
WHERE Duration > 300;

完全なクエリの結果は次のとおりです。

FirstName
Alice 1
Catalina 0
David 0
Lea 0
Marc 0

実行プランは次のとおりです。

スカラー サブクエリ演算子

この実行プランでは、集計演算子の上にスカラー サブクエリがあります(Scalar Subquery として示されています)。

パフォーマンスを改善するため、Cloud Spanner がスカラー サブクエリを別の演算子(結合、クロス結合など)に変換する場合があります。

たとえば、次のクエリについて考えます。

SELECT *
FROM Songs
WHERE Duration = (SELECT MAX(Duration) FROM Songs);

SQL サブ式は次のようになります。

SELECT MAX(Duration) FROM Songs;

完全なクエリの結果は次のとおりです。

SingerId AlbumId TrackId SongName Duration SongGenre
2 1 6 Nothing Is The Same 303 BLUES

実行プランは次のとおりです。

プランに含まれないスカラー サブクエリ演算子

Cloud Spanner がスカラー サブクエリをクロス適用に変更したため、この実行プランにはスカラー サブクエリが含まれていません。

配列サブクエリ

配列サブクエリはスカラー サブクエリに似ていますが、複数の入力行を使用できる点が異なります。使用した行は 1 つのスカラー出力配列に変換され、使用した入力行ごとに 1 つの要素を含む配列が作成されます。

たとえば、次のクエリについて考えます。

SELECT a.AlbumId,
ARRAY(SELECT ConcertDate
      FROM Concerts
      WHERE Concerts.SingerId = a.SingerId)
FROM Albums AS a;

サブクエリは次のようになります。

SELECT ConcertDate
FROM Concerts
WHERE Concerts.SingerId = a.SingerId;

AlbumId のサブクエリの結果が の ConcertDate 行から構成される配列に変換されます。この実行プランには、分散ユニオン演算子の上に Array Subquery という配列サブクエリがあります。

配列サブクエリ演算子

分散演算子

ここまでに説明した演算子は単一マシンの境界内で実行されます。分散演算子は、複数のサーバー間で実行されます。

次の演算子は分散演算子です。

分散ユニオン演算子はプリミティブ演算子で、この演算子から分散クロス適用、分散外部適用が派生しています。

実行プランでは、1 個以上のローカル分散ユニオン変数の上に分散演算子が分散ユニオン変数と一緒に存在します。分散ユニオン変数は、サブプランのリモート分散を実行します。ローカル分散ユニオン変数は、次の実行プランのように、クエリで実行されるスキャンの上に存在します。

分散演算子

ローカル分散ユニオン変数により、スプリットの境界が動的に変更され、再起動が発生してもクエリが安定して実行されます。

可能であれば、分散ユニオン変数にはスプリットのプルーニングを行う述語が設定されます。リモート サーバーは、述語の条件を満たすスプリットにのみサブプランを実行します。これにより、レイテンシとクエリ全体のパフォーマンスが向上します。

分散ユニオン

概念的には、分散ユニオン演算子は、1 つ以上のテーブルを複数のスプリットに分割し、各スプリットのサブクエリをリモートで個別に評価してから、すべての結果を結合します。

たとえば、次のクエリについて考えます。

SELECT s.SongName, s.SongGenre
FROM Songs AS s
WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK';

結果は次のようになります。

SongName SongGenre
Starting Again ROCK
The Second Time ROCK
Fight Story ROCK

実行プランは次のとおりです。

分散ユニオン演算子

分散ユニオン演算子はリモート サーバーにサブプランを送信します。これにより、スプリット全体にテーブル スキャンを実行し、クエリの述語 WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK' を満たすものを探します。結果のシリアル化演算子は、テーブル スキャンによって返された行から SongNameSongGenre の値を導きます。分散ユニオン演算子は、リモート サーバーから受信し、結合した結果を SQL クエリの結果として返します。

分散クロス適用

分散クロス適用(DCA)演算子は、クロス適用演算子を拡張して複数のサーバー全体で実行します。DCA の入力側が行のバッチをグループ化します。通常のクロス適用演算子と異なり、同時に複数の入力を処理できます。DCA マップ側は、リモート サーバーでクロス適用演算子を実行します。

たとえば、次のクエリについて考えます。

SELECT AlbumTitle FROM Songs
JOIN Albums ON Albums.AlbumId=Songs.AlbumId;

結果は次の形式になります。

AlbumTitle
Green
Nothing To Do With Me
Play
Total Junk
Green

実行プランは次のとおりです。

分散クロス適用演算子

DCA の入力には、AlbumIdSingerId のデータの行のバッチを作成する Albums テーブルのインデックス スキャンが含まれます。クロス適用演算子のマップ側は、インデックス SongsBySingerAlbumSongNameDesc に対するインデックス スキャンです。これは、入力行の SingerId の述語の影響を受け、SongsBySingerAlbumSongNameDesc インデックスの SingerId キーと比較されます。マッピングの結果、バッチが作成された入力行の SingerId 値の SongName が返されます。

この例の DCA プロセスを要約すると、DCA の入力は Albums テーブルから抽出された行で、DCA の出力はインデックス スキャンのマップに一致する行になります。

分散外部適用

分散外部適用演算子は、分散クロス適用演算子がクロス適用演算子を拡張するのと同様に、外部適用演算子を拡張して複数のサーバー全体で実行します。

たとえば、次のクエリについて考えます。

SELECT AlbumTitle FROM Songs
LEFT OUTER JOIN@{JOIN_TYPE=APPLY_JOIN} Albums
ON Albums.AlbumId=Songs.AlbumId;

結果は次の形式になります。

AlbumTitle
Green
Nothing To Do With Me
Play
Total Junk
Green

実行プランは次のとおりです。

分散外部適用演算子

詳細情報

次に、単独の演算子ではありませんが、前述の 1 つ以上の演算子をサポートする演算子について説明します。技術的にみると、ここに説明する項目は技術的な演算子ですが、クエリ実行計画では独立した演算子になっていません。

構造体コンストラクタ

構造体コンストラクタは、構造体またはフィールドの集合体を作成します。通常、計算オペレーションで生成された行に構造体を作成します。構造体コンストラクタは、独立した演算子ではありません。常に構造体計算演算子または結果のシリアル化演算子の中で使用されます。

構造体計算の場合、構造体コンストラクタが構造体を作成し、計算された行の列が 1 つの変数で構造体を参照できます。

結果のシリアル化の場合、構造体コンストラクタが結果のシリアル化に使用する構造体を作成します。

たとえば、次のクエリについて考えます。

SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;

結果は次のようになります。

A
1

実行プランは次のとおりです。

構造体コンストラクタ

この実行プランでは、構造体コンストラクタが結果のシリアル化演算子の中で使用されています。