查詢執行計畫

簡介

本頁面提供查詢執行計畫的概念,以及 Cloud Spanner 如何運用這些計畫,在分散式環境中執行查詢。如要瞭解使用 GCP 主控台擷取特定查詢的執行計畫,請參閱瞭解 Cloud Spanner 執行查詢的方式

Cloud Spanner 使用宣告式 SQL 陳述式來查詢其資料庫。SQL 陳述式會定義使用者想要的「內容」,不會指定取得結果的「方法」。「查詢執行計劃」是一組如何取得結果的步驟。對於特定的 SQL 陳述式,取得結果的方式可能有很多種。Cloud Spanner 查詢編譯器會在評估不同的方法後,產生最有效率的查詢執行計劃。接著,Cloud Spanner 便會使用該執行計劃來擷取結果。

就概念上而言,執行計劃就是相關運算子的樹狀結構。每個運算子都會從輸入讀取資料列,並產生輸出的資料列。系統會傳回執行作業根部的運算子結果做為 SQL 查詢的結果。

此查詢的範例為:

SELECT s.SongName FROM Songs AS s;

查詢執行計劃的結果看起來像這樣:

範例查詢執行計劃

此主題中的查詢和執行計劃是根據下列資料庫結構定義:

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);

即使資料表中沒有資料,也可以執行查詢並擷取執行計劃。

由於 Cloud Spanner 會將資料區分成拆分,因此取得有效率的執行計畫會變得很有挑戰性。拆分可獨立移動並指派到位於不同實體地點的不同伺服器。為了評估分散資料的執行計劃,Cloud Spanner 會依據下列條件採用執行作業:

  • 在包含資料的伺服器中,在本機執行「子計劃」
  • 使用積極分散式縮減,自動化調度管理與匯總多項遠端執行作業

Cloud Spanner 使用原始運算子 distributed union 及其變數 distributed cross applydistributed outer apply 來啟用這個模式。

查詢的作業流程

系統會將 Cloud Spanner 中的 SQL 查詢編譯成執行計劃,然後再傳送到初始「根」伺服器執行。系統會選擇使用最少躍點即可到達查詢資料的根伺服器。接著,根伺服器會:

  • 啟動子計劃的遠端執行 (如有必要)
  • 等待遠端執行的結果。
  • 處理任何剩餘的本機執行步驟,例如匯總結果
  • 傳回查詢的結果

接收到子計劃的遠端伺服器會做為其子計劃的「根」伺服器,並遵循頂層根伺服器的模式執行。結果會是遠端執行作業的樹狀結構。概念上,查詢執行流程是從上到下,而查詢結果則是從下到上傳回。下列圖表顯示這個模式。

概念查詢計劃

以下範例會更清楚說明這個模式。

匯總查詢

匯總查詢會實作 GROUP BY 查詢。

例如使用這個查詢:

SELECT s.SingerId, COUNT(*) AS SongCount
FROM Songs AS s
WHERE s.SingerId < 100
GROUP BY s.SingerId;

結果會是:

+----------+-----------+
| SingerId | SongCount |
+----------+-----------+
|        3 |         1 |
|        2 |         8 |
+----------+-----------+

概念上,下方是執行計劃:

匯總查詢執行計劃

Cloud Spanner 傳送執行計劃到與查詢執行合作的根伺服器,然後執行子計劃的遠端分散作業。

此執行計畫以 distributed union 開始,發送子計畫到拆分滿足 SingerId < 100 的遠端伺服器。計劃稍後顯示的本機分散式聯集代表遠端伺服器的執行作業。每個本機分散式聯集都會依據 Songs 表格的拆分,根據篩選條件 SingerId < 100,對子查詢進行個別評估。本機分散式聯集會將結果傳回匯總運算子。匯總運算子會依 SingerId 執行 COUNT 匯總,並將結果傳回序列化結果運算子。序列化結果運算子會將結果序列化,變成包含依 SingerId 編排歌曲計數的資料列。接著,分散式聯集會集結所有結果,然後傳回查詢結果。

如要進一步瞭解匯總,請參閱匯總運算子

共置彙整查詢

系統將交錯式資料表與其相關資料表的資料列儲存在同個位置。「共置彙整」指的是交錯資料表之間的彙整。共置彙整比需要索引或後端的彙整更具效能優勢。

例如使用這個查詢:

SELECT al.AlbumTitle, so.SongName
FROM Albums AS al, Songs AS so
WHERE al.SingerId = so.SingerId AND al.AlbumId = so.AlbumId;

(這個查詢假設 SongsAlbums 交錯)。

結果會是:

+-----------------------+--------------------------+
| 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 Us Get Back Together |
| Green                 | I Knew You Were Magic    |
| Green                 | Blue                     |
| Green                 | 42                       |
| Terrified             | Fight Story              |
+-----------------------+--------------------------+

以下為執行計劃:

共置彙整查詢執行計劃

此執行計畫從分散式聯集開始,將子計畫發布到具有 Albums 資料表拆分的遠端伺服器。由於 SongsAlbums 的交錯式資料表,每個遠端伺服器都能在各個遠端伺服器執行整個子計劃,不需要與不同的伺服器彙整。

子計劃包含交叉套用。每個交叉套用都會在資料表 Albums 上執行資料表掃描,以擷取 SingerIdAlbumIdAlbumTitle。然後,交叉套用會將資料表掃描的輸出,對應到 SongsBySingerAlbumSongNameDesc 索引的索引掃描輸出,並在符合資料表掃描輸出的 SingerId 的索引中,套用 SingerId篩選器。每個交叉套用都會傳送結果到序列化結果運算子,將 AlbumTitleSongName 資料序列化,再將結果傳回本機的分散式聯集。分散式聯集匯總本機分散式聯集的結果,接著傳回這些結果做為查詢結果。

索引與後端彙整查詢

以上範例使用兩個資料表的彙整,其中一個資料表與另一個資料表交錯。當兩個資料表沒有交錯,或一個資料表和一個索引沒有交錯時,執行計劃會較複雜,效率也比較差。

建議使用以下指令建立索引:

CREATE INDEX SongsBySongName ON Songs(SongName)

請在下方查詢中使用這個索引:

SELECT s.SongName, s.Duration
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");

結果會是:

+----------+----------+
| SongName | Duration |
+----------+----------+
| Blue     |      238 |
+----------+----------+

以下為執行計劃:

後端彙整查詢執行計劃

由於 SongsBySongName 索引不包含 Duration 資料欄,而使產生的執行計劃變得複雜。為了取得 Duration 值,Cloud Spanner 必須在「後端彙整」索引的結果到 Songs 資料表。這僅是彙整,不是共置,因為 Songs 資料表與全域索引 SongsBySongName 並未交錯。產生的查詢計劃會比共置彙整範例更複雜,是因為 Cloud Spanner 在資料位於不同位置時會執行最佳化以加速執行作業。

頂層的運算子是分散式交叉套用。此運算子的輸入端是來自 SongsBySongName 索引的資料列批次,滿足述詞 STARTS_WITH(s.SongName, "B")。接著分散式交叉套用會將這些批次對應到拆分中包含 Duration 資料的遠端伺服器。遠端伺服器使用資料表掃描來擷取 Duration 資料欄。資料表掃描使用 Condition:($Songs_key_TrackId' = $batched_Songs_key_TrackId) 篩選器,將 Songs 資料表的 TrackId 彙整到來自 SongsBySongName 索引批次的資料列的 TrackId

系統會匯總結果取得最終的查詢答案。另一方面,分散式交叉套用的輸入端會包含分散式聯集/本機分散式聯集組合,評估滿足述詞 STARTS_WITH 的索引資料列。

建議執行有些不同的查詢,不選用 s.Duration 資料欄:

SELECT s.SongName
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");

此查詢作業可完整發揮索引的功能,如下方執行計劃所示:

簡易查詢執行計劃

由於查詢要求的所有資料欄都在索引中,此執行計劃不需要後端彙整。

後續步驟

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Cloud Spanner 說明文件