「binary」運算子有兩個關聯子項。以下運算子屬於二進位運算子:
資料庫結構定義
本頁的查詢和執行計畫是根據下列資料庫結構定義:
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");
套用彙整
套用聯結是 Spanner 使用的主要聯結運算子。Apply join 運算子會執行資料列導向的處理,不像其他執行以組合為基礎的處理程序的運算子 (如 hash join)。apply 運算子包含兩種輸入:input (左側子項) 和 map (右側子項)。apply 運算子會使用 apply 方法,將輸入端的每個資料列套用至對應端:cross、outer、semi 或 anti-semi。此外,套用聯結的變體也會顯示在「分散式套用」的地圖端。
在下列情況下,套用聯結運算子最有效率:
- 輸入的基數較低。
- 彙整索引鍵是對應端主鍵的前置字串。
- 這項查詢會彙整兩個交錯資料表。
屬性和執行作業統計資料
運算子的屬性會說明運算子執行時使用的特徵。執行統計資料是在查詢執行期間收集的值,可協助您評估運算子的效能。
屬性
| 名稱 | 說明 |
|---|---|
| 執行方法 | 在列執行中,運算子一次處理一列。 在批次執行中,運算子會一次處理一批資料列。 |
執行作業統計資料
| 名稱 | 說明 |
|---|---|
| 延遲時間 | 運算子中所有執行作業的經過時間。 |
| 累計延遲時間 | 目前運算子及其後代的總時間。 |
| CPU 作業時間 | 執行運算子所耗費的 CPU 作業時間總和。 |
| 累計 CPU 作業時間 | 執行運算子及其後代所花費的 CPU 作業時間總計。 |
| 執行時間 | 執行查詢及處理結果所花費的總時間。 |
| 傳回的資料列數 | 這個運算子輸出的資料列數 |
| 執行作業數量 | 運算子的執行次數。部分執行作業可以平行執行。 |
Cross apply
Cross apply 會執行內部聯結,只傳回相符的資料列。
下列查詢會示範這個運算子:
這項查詢會要求每個歌手的名字,以及該歌手其中一首歌曲的名稱。
SELECT si.firstname,
(SELECT so.songname
FROM songs AS so
WHERE so.singerid = si.singerid
LIMIT 1)
FROM singers AS si;
/*-----------+--------------------------+
| FirstName | Unspecified |
+-----------+--------------------------+
| Alice | Not About The Guitar |
| Catalina | Let's Get Back Together |
| David | NULL |
| Lea | NULL |
| Marc | NULL |
+-----------+--------------------------*/
這項查詢會從 Singers 資料表填入第一欄,並從 Songs 資料表填入第二欄。當 Singers 資料表中有 SingerId,但 Songs 資料表中沒有對應的 SingerId 時,第二欄會包含 NULL。
執行計畫如下:

頂層節點的運算子是 distributed union 運算子。distributed union 運算子會將子計畫分配到遠端伺服器。子計畫包含 serialize result 運算子,會運算歌手的名字和該歌手其中一首歌曲的名稱,並且針對輸出的每一個資料列進行序列化。
serialize result 運算子會從 cross apply 運算子接受輸入。cross apply 運算子的輸入端是在 Singers 資料表上的 table scan。
執行計畫會繼續進行,如下所示:

cross apply 運算的對應端包含以下內容 (從上至下):
- aggregate 運算子,傳回
Songs.SongName。 - limit 運算子,將傳回的歌曲數量限制為每位歌手一首。
- 在
SongsBySingerAlbumSongNameDesc索引上進行 index scan。
cross apply 運算子會將輸入端的每個資料列,對應到對應端中具有相同 SingerId 的資料列。cross apply 運算子輸出是輸入列的 FirstName 值,以及來自對應列的 SongName 值。
(如果沒有對應到 SingerId 的對應列,SongName 值將是 NULL。) 接著,位於執行計畫頂層的 distributed union 運算子會結合所有來自遠端伺服器的輸出列,做為查詢結果傳回。
Outer apply
outer apply 提供 left outer join 語意。這個運算子會在必要時新增 NULL 填補,藉此確保對應端每次執行都會傳回至少一個資料列。
Semi apply
只有在對應側發生相符情況時,「semi apply」運算子才會傳回輸入資料欄。
下列查詢會使用半聯結,找出有專輯的歌手:
SELECT
FirstName,
LastName
FROM
Singers
WHERE
SingerId IN (
SELECT
SingerId
FROM
Albums);
/*-----------+----------+
| FirstName | LastName |
+-----------+----------+
| Marc | Richards |
| Catalina | Smith |
| Alice | Trentor |
| Lea | Martin |
+-----------+----------*/
方案區隔如下所示:

Anti-semi apply
「Anti-semi apply」運算子與「semi apply」運算子類似,但只會在對應端沒有相符項目時,傳回輸入資料表欄。
下列查詢會使用反半聯結,找出沒有專輯的歌手:
SELECT
FirstName,
LastName
FROM
Singers
WHERE
SingerId NOT IN (
SELECT
SingerId
FROM
Albums);
/*-----------+----------+
| FirstName | LastName |
+-----------+----------+
| David | Lomond |
+-----------+----------*/
方案區隔如下所示:

Hash join
「hash join」運算子是 SQL join 的雜湊實作。Hash join 執行以組合為基礎的處理程序。hash join 運算子會從標示為 build (左側子項) 的輸入讀取資料列,並根據 join 條件插入雜湊表。hash join 運算子接著會從標示為 probe (右側子項) 的輸入讀取資料列。針對每個從 probe 輸入讀取的資料列,hash join 運算子會在雜湊表中查詢相符的資料列。hash join 運算子會傳回相符的資料列做為結果。
雜湊聯結具有下列優點:
- 不需要排序輸入內容
- 建構雜湊表時,系統會計算 Bloom 篩選器。運算子會使用篩選器,從探查端排除沒有相符項的資料列。請注意,這是剩餘篩選條件,不是搜尋篩選條件。
下列查詢會示範這個運算子:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=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 |
+-----------------------+--------------------------*/
執行計畫區隔如下所示:

在執行計畫中,「build」是分散式聯集,會將掃描分配到 Albums 資料表。「Probe」是分散式聯集運算子,可將掃描分配到 SongsBySingerAlbumSongNameDesc 索引上。hash join 運算子會讀取所有來自建置端的資料列。系統會根據條件 a.SingerId =
s.SingerId AND a.AlbumId = s.AlbumId 中的資料欄,將每個建構資料列放入雜湊表。接著 hash join 運算子會從探測端讀取所有資料列。針對每個探測資料列,hash join 運算子會查詢雜湊表中相符的內容。hash join 運算子會傳回符合的結果。
雜湊表中相符的結果在傳回前,可能會由剩餘條件篩選。(剩餘條件出現的位置可能會在非相等的聯結)。由於記憶體管理和聯結變數,Hash join 執行計畫可能會很複雜。主要的 hash join 演算法會經過調整,以處理內部變數、半變數、反變數和外部聯結變數。
屬性和執行作業統計資料
運算子的屬性會說明運算子執行時使用的特徵。執行統計資料是在查詢執行期間收集的值,可協助您評估運算子的效能。
屬性
| 名稱 | 說明 |
|---|---|
| 執行方法 | 在列執行中,運算子一次處理一列。 在批次執行中,運算子會一次處理一批資料列。 |
執行作業統計資料
| 名稱 | 說明 |
|---|---|
| 延遲時間 | 運算子中所有執行作業的經過時間。 |
| 累計延遲時間 | 目前運算子及其後代的總時間。 |
| CPU 作業時間 | 執行運算子所耗費的 CPU 作業時間總和。 |
| 累計 CPU 作業時間 | 執行運算子及其後代所花費的 CPU 作業時間總計。 |
| 執行時間 | 執行查詢及處理結果所花費的總時間。 |
| 傳回的資料列數 | 這個運算子輸出的資料列數 |
| 執行作業數量 | 運算子的執行次數。部分執行作業可以平行執行。 |
合併彙整
「merge join」運算子是 SQL join 的合併實作。聯結的兩側都會產生資料列,並依聯結條件中使用的資料欄排序。合併聯結會同時耗用兩個輸入串流,並在符合聯結條件時輸出資料列。如果輸入內容未排序,最佳化工具會在計畫中加入明確的 Sort 運算子。
合併聯結具有下列優點:
- 如果資料已排序,則不需要任何記憶體。
- 即使資料未排序,分散式聯結也能對每個個別分割執行排序,而不是在根目錄上建立大型雜湊表。
最佳化工具不會自動選取合併聯結,如要使用這個運算子,請在查詢提示中將聯結方法設為 MERGE_JOIN,如下列範例所示:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
/*-----------------------+--------------------------+
| AlbumTitle | SongName |
+-----------------------+--------------------------+
| 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 |
| Nothing To Do With Me | Not About The Guitar |
+-----------------------+--------------------------*/
執行計畫如下所示:

在這個執行計畫中,合併聯結會分散,以便在資料所在位置執行聯結。此外,由於兩個資料表掃描作業都已依 SingerId 和 AlbumId (聯結條件) 排序,因此本範例中的合併聯結作業不需要額外的排序運算子即可運作。在這個計畫中,每當左側掃描的 Albums 資料表 SingerId、AlbumId 小於右側掃描的 SingerId_1、AlbumId_1 值時,左側掃描就會前進。同樣地,只要右側掃描的值小於左側掃描的值,右側掃描就會前進。這項合併作業會繼續搜尋對等項目,以傳回相符的資料列。
請參考以下查詢,瞭解另一個合併聯結範例:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.albumid = s.albumid;
/*-----------------------+--------------------------+
| AlbumTitle | SongName |
+-----------------------+--------------------------+
| Total Junk | The Second Time |
| Total Junk | Starting Again |
| Total Junk | Nothing Is The Same |
| Total Junk | Let's Get Back Together |
| Total Junk | I Knew You Were Magic |
| Total Junk | Blue |
| Total Junk | 42 |
| Total Junk | 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 |
| Green | Not About The Guitar |
| Nothing To Do With Me | The Second Time |
| Nothing To Do With Me | Starting Again |
| Nothing To Do With Me | Nothing Is The Same |
| Nothing To Do With Me | Let's Get Back Together |
| Nothing To Do With Me | I Knew You Were Magic |
| Nothing To Do With Me | Blue |
| Nothing To Do With Me | 42 |
| Nothing To Do With Me | Not About The Guitar |
| Play | The Second Time |
| Play | Starting Again |
| Play | Nothing Is The Same |
| Play | Let's Get Back Together |
| Play | I Knew You Were Magic |
| Play | Blue |
| Play | 42 |
| Play | Not About The Guitar |
| Terrified | Fight Story |
+-----------------------+--------------------------*/
執行計畫如下所示:

在上述執行計畫中,查詢最佳化工具導入了額外的排序運算子,以執行合併聯結。這個範例查詢中的 JOIN 條件只適用於 AlbumId,但資料並非以這種方式儲存,因此必須新增排序條件。查詢引擎支援分散式合併演算法,可讓排序作業在本機進行,而非全域排序,進而分散及平行處理 CPU 成本。
相符的結果也可能會由剩餘條件篩選。舉例來說,剩餘條件會出現在非相等的聯結中。由於額外的排序需求,Merge join 執行計畫可能會很複雜。主要的 merge join 演算法會處理內部變數、半變數、反變數和外部聯結變數。
屬性和執行作業統計資料
運算子的屬性會說明運算子執行時使用的特徵。執行統計資料是在查詢執行期間收集的值,可協助您評估運算子的效能。
屬性
| 名稱 | 說明 |
|---|---|
| 執行方法 | 在列執行中,運算子一次處理一列。 在批次執行中,運算子會一次處理一批資料列。 |
執行作業統計資料
| 名稱 | 說明 |
|---|---|
| 延遲時間 | 運算子中所有執行作業的經過時間。 |
| 累計延遲時間 | 目前運算子及其後代的總時間。 |
| CPU 作業時間 | 執行運算子所耗費的 CPU 作業時間總和。 |
| 累計 CPU 作業時間 | 執行運算子及其後代所花費的 CPU 作業時間總計。 |
| 執行時間 | 執行查詢及處理結果所花費的總時間。 |
| 傳回的資料列數 | 這個運算子輸出的資料列數 |
| 執行作業數量 | 運算子的執行次數。部分執行作業可以平行執行。 |
遞迴聯集
「recursive union」運算子會對兩個輸入執行聯集,一個代表 base 案例,另一個代表 recursive 案例。用於圖形查詢,並搭配量化路徑遍歷。系統會先處理基礎輸入內容,且只處理一次。系統會處理遞迴輸入,直到遞迴終止為止。如果指定上限,達到上限時遞迴就會終止;如果遞迴未產生任何新結果,也會終止。在下列範例中,Collaborations 資料表會新增至結構定義,並建立名為 MusicGraph 的屬性圖。
CREATE TABLE Collaborations (
SingerId INT64 NOT NULL,
FeaturingSingerId INT64 NOT NULL,
AlbumTitle STRING(MAX) NOT NULL,
) PRIMARY KEY(SingerId, FeaturingSingerId, AlbumTitle);
CREATE OR REPLACE PROPERTY GRAPH MusicGraph
NODE TABLES(
Singers
KEY(SingerId)
LABEL Singers PROPERTIES(
BirthDate,
FirstName,
LastName,
SingerId,
SingerInfo)
)
EDGE TABLES(
Collaborations AS CollabWith
KEY(SingerId, FeaturingSingerId, AlbumTitle)
SOURCE KEY(SingerId) REFERENCES Singers(SingerId)
DESTINATION KEY(FeaturingSingerId) REFERENCES Singers(SingerId)
LABEL CollabWith PROPERTIES(
AlbumTitle,
FeaturingSingerId,
SingerId),
);
以下圖形查詢會找出與特定歌手合作過的歌手,或是與這些合作歌手合作過的歌手。
GRAPH MusicGraph
MATCH (singer:Singers {singerId:42})-[c:CollabWith]->{1,2}(featured:Singers)
RETURN singer.SingerId AS singer, featured.SingerId AS featured

遞迴聯集運算子會篩選 Singers 資料表,找出具有指定 SingerId 的歌手。這是遞迴聯集的基本輸入內容。遞迴聯集的遞迴輸入內容包含 分散式交叉套用或其他查詢的聯結運算子,這些查詢會重複將 Collaborations 資料表與前一次聯結疊代的結果聯結。基礎輸入表單中的資料列會形成第零次疊代。在每次疊代時,疊代的輸出內容會由遞迴緩衝區掃描儲存。遞迴假脫機掃描中的資料列會與 spoolscan.featuredSingerId = Collaborations.SingerId 上的 Collaborations 資料表彙整。由於查詢中指定的上限為兩次,因此遞迴會在完成兩次疊代後終止。
屬性和執行作業統計資料
運算子的屬性會說明運算子執行時使用的特徵。執行統計資料是在查詢執行期間收集的值,可協助您評估運算子的效能。
屬性
| 名稱 | 說明 |
|---|---|
| 執行方法 | 在列執行中,運算子一次處理一列。 在批次執行中,運算子會一次處理一批資料列。 |
執行作業統計資料
| 名稱 | 說明 |
|---|---|
| 延遲時間 | 運算子中所有執行作業的經過時間。 |
| 累計延遲時間 | 目前運算子及其後代的總時間。 |
| CPU 作業時間 | 執行運算子所耗費的 CPU 作業時間總和。 |
| 累計 CPU 作業時間 | 執行運算子及其後代所花費的 CPU 作業時間總計。 |
| 執行時間 | 執行查詢及處理結果所花費的總時間。 |
| 傳回的資料列數 | 這個運算子輸出的資料列數 |
| 執行作業數量 | 運算子的執行次數。部分執行作業可以平行執行。 |