結構定義總覽

本頁面將說明 Spanner 結構定義規定、如何使用結構定義建立階層關係,以及結構定義功能。此外,它還會導入交錯式資料表,這可在查詢上層/下層關係的資料表時,改善查詢效能。

結構定義是包含資料庫物件 (例如資料表、檢視表、索引和函式) 的命名空間。您可以使用結構定義來整理物件、套用精細的存取權控管權限,以及避免命名衝突。您必須為 Spanner 中的每個資料庫定義結構定義。

您也可以為不同地理區域的資料庫資料表,進一步區隔及儲存資料列。詳情請參閱區域劃分總覽

強型資料

Spanner 中的資料為強型別。資料類型包括純量和複雜類型,請參閱「GoogleSQL 中的資料類型」和「PostgreSQL 資料類型」瞭解相關資訊。

選擇主要金鑰

Spanner 資料庫可包含一或多個資料表。表格結構為列和欄。資料表結構定義一或多個資料表欄為資料表的主鍵,用來唯一識別每個資料列。主鍵一律會編入索引,以便快速查詢資料列。如要更新或刪除資料表中的現有資料列,則該資料表必須具有主鍵。沒有主鍵資料欄的資料表只能擁有一個資料列。只有 GoogleSQL 方言資料庫可以包含沒有主鍵的資料表。

您的應用程式通常已有非常適合當做主鍵使用的欄位。例如,對於 Customers 資料表,應用程式可能已提供非常適合當主鍵的 CustomerId。在其他情況下,您可能需要在插入資料列時產生主鍵。這個值通常是沒有業務意義的專屬整數值 (代理主鍵)。

在所有情況下,您都應該要小心,避免因為選錯主鍵而發生資源使用率不均的情況。舉例來說,如果您插入的記錄是以單調遞增整數做為索引鍵,則一律會在索引鍵空間的尾端插入資料。這不是一個好的做法,因為 Spanner 會依據索引鍵範圍將資料分配到各伺服器,也就是說,您插入的資料會被引導至單一伺服器,而導致資源使用率不均。您可善用下列技術,將負載分散到多部伺服器上,以避免發生資源使用率不均的情形。

父項/子項資料表關係

在 Spanner 中定義父項/子項關係有兩種方式:資料表交錯外鍵

Spanner 的資料表交錯功能相當適合用於許多父項/子項關係。透過交錯,Spanner 會在儲存空間中將子項資料列與父項資料列實體並置。共置可大幅提升效能。舉例來說,如果您有 Customers 資料表和 Invoices 資料表,而且應用程式經常擷取特定客戶的所有月結單,則可將 Invoices 定義為 Customers 的交錯子項資料表。這樣一來,您就等同於宣告兩個獨立資料表之間存在資料位置關係。您告訴 Spanner 儲存一或多個 Invoices 資料列,以及一個 Customers 資料列。當與 INTERLEAVE IN PARENT 子句交錯時,系統會強制執行此上層/子項關係。INTERLEAVE IN 子項資料表共用相同的實體資料列交錯特性,但 Spanner 不會在父項和子項之間強制執行參考完整性。

您可以使用 DDL 將子項資料表與父項資料表建立關聯,方法是宣告子項資料表為父項資料表的交錯資料表,並將父項資料表主鍵納入子項資料表複合主鍵的第一部分。

如要進一步瞭解交錯功能,請參閱「建立交錯資料表」。

外鍵是較為常見的父項子項關係解決方案,也能用於其他用途。外鍵並非僅限於主鍵欄,資料表可以同時含有多組外鍵關係,在某些關係中擔任父項,在其他關係中擔任子項。不過,外鍵關係並未表示資料表會存放在儲存空間層中的相同位置。

Google 建議您選擇以交錯資料表或外鍵呈現父項子項關係,但請勿兩者並用。如要進一步瞭解外鍵及其與交錯資料表的比較,請參閱「外鍵總覽」。

交錯式資料表中的主鍵

若要交錯排列,每個資料表都必須有主鍵。如果您宣告某個資料表為另一個資料表的交錯子項,該資料表必須具有複合主鍵,其中包含父項主鍵的所有元件,並以相同順序排列,通常還會加上一或多個額外的子項資料表欄。

Spanner 會依據主鍵值的排序來儲存資料列,並且在父項資料列之間插入子項資料列。請參閱本頁稍後的建立交錯資料表一節,瞭解交錯資料列的插圖。

簡而言之,Spanner 可將相關資料表的資料列實體儲存於相同的位置。結構定義範例將說明這項實體配置看起來的樣子。

資料庫分割

您可以在最多七層深的資料表之間定義交錯式父項/子項階層關係,也就是說,您可以將七個獨立資料表的資料列放在同一個位置。如果資料表中的資料不大,單一 Spanner 伺服器可能就能處理資料庫。但是當相關資料表變大,開始達到個別伺服器的資源限制時會發生什麼事?Spanner 屬於分散式資料庫,因此隨著資料庫增長,Spanner 會將資料拆成名為「分割」的區塊。個別分割可獨立移動,並指派給位於不同實體位置的不同伺服器。分割項目會保留一連串相鄰的資料列。此範圍內的起始及結束索引鍵稱為「分割界線」。Spanner 會根據大小和負載自動新增和移除分割界線,進而變更資料庫中的分割數量。

依負載進行分割

做為 Spanner 依負載進行分割以解決讀取資源使用率不均的範例之一,假設資料庫包含一個資料表,其中有 10 個資料列的讀取頻率遠高於其他資料列,Spanner 可在每個 10 個資料列之間新增分割邊界,讓每個資料列由不同的伺服器處理,而非讓這些資料列的所有讀取作業都使用單一伺服器的資源。

一般來說,如果您遵循結構定義設計的最佳做法,Spanner 就能減少資源使用率不均現象,讓讀取總處理量每隔幾分鐘就會改善,直到執行個體中的資源飽和為止,或是無法新增新的分割界線 (因為分割範圍只涵蓋單一資料列,且沒有交錯的子項)。

命名結構定義

命名結構定義可協助您將類似資料整理在一起。這有助於您在 Google Cloud 主控台中快速尋找物件、套用權限,並避免命名衝突。

命名結構定義與其他資料庫物件一樣,可透過 DDL 進行管理。

Spanner 命名結構定義可讓您使用完整的名稱 (FQN) 查詢資料。您可以使用 FQN 結合結構定義名稱和物件名稱,用於識別資料庫物件。舉例來說,您可以為倉庫業務單位建立名為 warehouse 的結構定義。使用此結構定義的資料表可能包括:productordercustomer information。或者,您可以為履行業務單位建立名為 fulfillment 的結構定義。這個結構定義也可能包含名為 productordercustomer information 的資料表。在第一個範例中,FQN 為 warehouse.product,在第二個範例中,FQN 為 fulfillment.product。這樣一來,當多個物件共用相同名稱時,就不會造成混淆。

CREATE SCHEMA DDL 中,資料表物件會同時獲得 FQN (例如 sales.customers) 和簡短名稱 (例如 sales)。

下列資料庫物件支援命名結構定義:

  • TABLE
    • CREATE
    • INTERLEAVE IN [PARENT]
    • FOREIGN KEY
    • SYNONYM
  • VIEW
  • INDEX
  • FOREIGN KEY
  • SEQUENCE

如要進一步瞭解如何使用命名結構定義,請參閱「管理命名結構定義」一文。

使用命名結構描述的精細存取權控管機制

命名結構定義可讓您授予結構定義層級存取權,用於結構定義中的每個物件。這項設定適用於您授予存取權時已存在的架構物件。您必須授予日後新增物件的存取權。

精細的存取權控管機制可限制整個資料庫物件群組的存取權,例如資料表、資料欄和資料表中的資料列。

詳情請參閱「為命名的結構定義授予精細的存取權控管權限」。

結構定義範例

本節的結構定義範例說明如何建立父項和子項資料表 (含/不含交錯),並說明資料的對應實體版面配置。

建立父項表

假設您正在建立音樂應用程式,需要一個資料表來儲存歌手資料的資料列:

具有五列四欄的「Singers」(歌手) 資料表

請注意,該資料表包含一個主鍵資料列 SingerId,位於粗線的左側。資料表是依據資料列和資料欄來整理。

您可以使用下列 DDL 定義資料表:

GoogleSQL

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

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

請注意下列結構定義範例的相關事項:

  • Singers 是位於資料庫階層根部的資料表 (因為我們未將此資料表定義為另一個資料表的交錯子項)。
  • 對於 GoogleSQL 方言資料庫,主鍵資料欄通常會加上 NOT NULL 註解 (但如果您允許在主鍵資料欄中使用 NULL 值,則可省略此註解)。詳情請參閱「關鍵欄」。
  • 未包含主鍵中的資料欄稱為非鍵欄,這種資料欄可包含選用的 NOT NULL 註解。
  • 在 GoogleSQL 中,採用 STRINGBYTES 類型的資料欄必須以長度來定義,此長度代表欄位中可儲存的 Unicode 字元上限 長度規格是 PostgreSQL varcharcharacter varying 類型的選用項目。如需更多資訊,請參閱 GoogleSQL 方言資料庫的「Scalar Data Types」和 PostgreSQL 方言資料庫的「PostgreSQL 資料類型」。

Singers 資料表中的資料列實體配置看起來會是什麼樣子?下圖顯示依據主鍵儲存的 Singers 資料表資料列,主鍵為「Singers(1)」,然後是「Singers(2)」,其中括號內的數字為主鍵值。

按主鍵順序儲存的資料表資料列範例

上圖顯示鍵值為 Singers(3)Singers(4) 的資料列之間的分割界線範例,將分割後的資料指派給不同的伺服器。這表示當此資料表增長時,即可將 Singers 資料的資料列儲存於不同的位置。

建立父項和子項資料表

假設您現在要將每位歌手的專輯基本資料新增至音樂應用程式。

具有五列三欄的「Albums」(專輯) 資料表

請注意,Albums 的主鍵是由 SingerIdAlbumId 兩個資料欄組成,以便建立專輯和歌手之間的關聯。下列結構定義範例會在資料庫階層根部定義 AlbumsSingers 資料表,讓這兩個資料表變成同層級資料表。

-- Schema hierarchy:
-- + Singers (sibling table of Albums)
-- + Albums (sibling table of Singers)

GoogleSQL

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

CREATE TABLE Albums (
SingerId     INT64 NOT NULL,
AlbumId      INT64 NOT NULL,
AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

CREATE TABLE albums (
singer_id     BIGINT,
album_id      BIGINT,
album_title   VARCHAR,
PRIMARY KEY (singer_id, album_id)
);

SingersAlbums 的資料列實體配置看起來像下圖,其中有由連續主鍵儲存的 Albums 資料表資料列,然後是由連續主鍵儲存的 Singers 資料列:

資料列實體配置

關於這個結構定義的重要注意事項,是 Spanner 假設 SingersAlbums 資料表之間沒有資料本地性關係,因為這兩者都是頂層資料表。當資料庫變大時,Spanner 即可在任何資料列之間新增分割界線。這表示 Albums 資料表的資料列的分割結果可能和 Singers 資料表的資料列不同,而且這兩個分割可獨立移動。

視應用程式的需求而定,您可以將 Albums 資料放在與 Singers 資料不同的分割上。不過,由於需要在不同資源之間協調讀取和更新作業,因此這可能會導致效能受損。如果應用程式常常需要擷取特定歌手所有專輯的相關資訊,那麼您應該建立 Albums 當做 Singers 的交錯子項資料表,如此即可在主鍵維度將這兩個資料表的資料列放置在相同位置。下一個範例會更詳細地說明這種做法。

建立交錯式資料表

交錯資料表是一個宣告為其他資料表交錯子項的資料表,因為您想將子項資料表的資料列與相關父項資料列儲存在一起。如先前所述,父項資料表主鍵必須是子項資料表複合式主鍵的第一部分。

資料表一經交錯就無法復原。您無法取消交錯。您必須重新建立資料表,然後將資料遷移至該資料表。

假設您在設計音樂應用程式時,發現應用程式在存取 Singers 資料列時,需要經常存取 Albums 資料表的資料列。舉例來說,當您存取 Singers(1) 列時,也必須存取 Albums(1, 1)Albums(1, 2) 列。在這種情況下,SingersAlbums 必須有密切的資料本地性關係。您可以建立 Albums 當做 Singers 的交錯子項資料表,藉以宣告這項資料本地性。

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)

下列結構定義中的粗體線說明如何建立 Albums 當做 Singers 的交錯資料表。

GoogleSQL

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

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

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

此結構定義的注意事項:

  • SingerId 是子項資料表 Albums 主鍵的第一個部分,也是其父項資料表 Singers 的主鍵。
  • ON DELETE CASCADE 註解表示如果在父項資料表刪除資料列,也會自動刪除其子項資料列。如果子項資料表沒有這項註解,或是註解為 ON DELETE NO ACTION,您必須先刪除子項資料列,才能刪除父項資料列。
  • 交錯資料列會先依照父項資料表的資料列排序,然後依照具有父項主鍵之子項資料表的連續資料列排序,例如「Singers(1)」、「Albums(1, 1)」和「Albums(1, 2)」。
  • 當此資料庫進行分割時,系統會保留每位歌手及其專輯資料的資料本地性,前提是 Singers 列和所有 Albums 列的大小都低於分割大小限制,且這些 Albums 列中都沒有熱點。
  • 父項資料列必須存在,您才能插入子項資料列。父項資料列可能已經存在於資料庫中,或者在相同交易中插入子項資料列之前插入。

「Albums」(專輯) 資料列在「Singers」(歌手) 資料列之間交錯

假設您想將 Projects 和其 Resources 模擬為交錯資料表。INTERLEAVE IN 可在某些情況下發揮作用,例如在 Projects 資料列不存在的情況下,仍可讓下方實體存在。舉例來說,如果專案已刪除,但其資源需要在刪除前先清理,這時就會用到 INTERLEAVE IN

GoogleSQL

CREATE TABLE Projects (
  ProjectId   INT64 NOT NULL,
  ProjectName STRING(1024),
) PRIMARY KEY (ProjectId);

CREATE TABLE Resources (
  ProjectId    INT64 NOT NULL,
  ResourceId   INT64 NOT NULL,
  ResourceName STRING(1024),
) PRIMARY KEY (ProjectId, ResourceId),
  INTERLEAVE IN Projects;

PostgreSQL

CREATE TABLE Projects (
  ProjectId   BIGINT PRIMARY KEY,
  ProjectName VARCHAR(1024),
);

CREATE TABLE Resources (
  ProjectId    BIGINT,
  ResourceId   BIGINT,
  ResourceName VARCHAR(1024),
  PRIMARY KEY (ProjectId, ResourceId)
) INTERLEAVE IN Projects;

請注意,在本範例中,我們使用的是 INTERLEAVE IN Projects 子句,而非 INTERLEAVE IN PARENT Projects。這表示我們不會在專案和資源之間強制建立父子關係。

在這個範例中,即使 Projects(1) 資料列不存在,資料庫中仍可存在 Resources(1, 10)Resources(1, 20) 資料列。即使 Resources(1, 10)Resources(1, 20) 仍存在,也可以刪除 Projects(1),而且刪除作業不會影響這些 Resources 資料列。

建立交錯資料表的階層

SingersAlbums 之間的父項/子項關係可延伸至更多下階資料表。舉例來說,您可以建立名為 Songs 的交錯資料表當做 Albums 的子項,以儲存每張專輯的歌曲清單:

具有六列四欄的「Songs」(歌曲) 資料表

Songs 的主鍵必須包含階層中較高層級資料表的所有主鍵,即 SingerIdAlbumId

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
--     + Songs (interleaved table, child table of Albums)

GoogleSQL

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

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

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

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

CREATE TABLE songs (
 singer_id     BIGINT,
 album_id      BIGINT,
 track_id      BIGINT,
 song_name     VARCHAR,
 PRIMARY KEY (singer_id, album_id, track_id)
 )
 INTERLEAVE IN PARENT albums ON DELETE CASCADE;

下圖代表交錯列的實體檢視畫面。

歌曲會在「Albums」(專輯) 中交錯,而「Albums」(專輯) 會在「Singers」(歌手) 之間交錯

在這個範例中,隨著歌手人數增加,Spanner 會在歌手之間加入分割邊界,以便保留歌手與其專輯和歌曲資料之間的資料本地性。不過,如果單一資料列及其子項資料列的大小超過分割大小限制,或是在子項資料列中偵測到熱點,Spanner 會嘗試新增分割邊界,以隔離該熱點資料列及其下方的所有子項資料列。

簡而言之,父項資料表及其所有子項和下階資料表在結構定義中構成資料表階層。雖然階層中每個資料表在邏輯上都是獨立的,但透過這種方式進行實體交錯,可提升效能、有效地預先彙整資料表、讓您一併存取相關資料列,同時減少儲存空間存取次數。

與交錯式資料表彙整

可能的話,利用主鍵將資料彙整於交錯的資料表中。由於每個交錯資料列通常會和其父項資料列以相同的分割方式儲存,因此 Spanner 可在本機執行主鍵彙整,減少儲存空間存取和網路流量。在下列範例中,SingersAlbums 是在主鍵 SingerId 上彙整。

GoogleSQL

SELECT s.FirstName, a.AlbumTitle
FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;

PostgreSQL

SELECT s.first_name, a.album_title
FROM singers AS s JOIN albums AS a ON s.singer_id = a.singer_id;

位置群組

Spanner 會使用區域群組,保留資料表欄之間的資料區域關係。如果您沒有明確為資料表建立任何區域群組,Spanner 會將所有欄分組為 default 區域群組,並將所有資料表的資料儲存在 SSD 儲存空間中。您可以使用區域群組執行下列操作:

  • 使用分層儲存空間。分層儲存空間是完全受管理的儲存空間功能,可讓您選擇將資料儲存在固態硬碟 (SSD) 或硬碟 (HDD) 中。根據預設,如果未使用分層儲存空間,Spanner 會將所有資料儲存在 SSD 儲存空間中。

  • 使用資料欄分組功能,將指定的資料欄與其他資料欄分開儲存。由於指定欄的資料會個別儲存,因此從這些欄讀取資料的速度會比將所有資料分組時快。如要使用資料欄群組,您必須建立區域群組,但不指定任何分層儲存空間選項。Spanner 會使用區域群組分別儲存指定的資料欄。如果指定,資料欄會從資料表或預設區域群組繼承分層儲存空間政策。接著,請使用 CREATE TABLE DDL 陳述式為指定的資料欄設定區域群組,或是使用 ALTER TABLE DDL 陳述式變更資料表資料欄使用的區域群組。DDL 陳述式會決定儲存在區域群組中的資料欄。最後,您可以更有效率地讀取資料

索引鍵資料欄

本節包含關鍵欄的相關說明。

變更表格索引鍵

資料表的索引鍵無法變更;您無法將索引鍵資料欄新增到現有資料表,或從現有資料表移除索引鍵資料欄。

在主鍵中儲存空值

在 GoogleSQL 中,如果您要在主鍵資料欄中儲存空值,請在結構定義中省略該資料欄的 NOT NULL 子句。(PostgreSQL 方言資料庫不支援主鍵欄中的空值)。

下列範例示範如何在主鍵資料欄 SingerId 上省略 NOT NULL 子句。請注意,由於 SingerId 是主鍵,因此該欄最多只能有一個資料列儲存 NULL

CREATE TABLE Singers (
  SingerId   INT64 PRIMARY KEY,
  FirstName  STRING(1024),
  LastName   STRING(1024),
);

在父項和子項資料表的宣告中,主鍵資料欄的 NULLABLE (可為空值) 屬性必須相符。在本範例中,Albums.SingerId 資料欄的 NOT NULL 不允許使用,因為 Singers.SingerId 會略過該欄。

CREATE TABLE Singers (
  SingerId   INT64 PRIMARY KEY,
  FirstName  STRING(1024),
  LastName   STRING(1024),
);

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

不允許的類型

下列資料欄不得採用 ARRAY 類型:

  • 資料表的索引鍵資料欄。
  • 索引的索引鍵資料欄。

多租戶架構設計

如果您要儲存屬於不同客戶的資料,則可能必須實作多租戶架構。舉例來說,音樂服務可能想要個別儲存每家獨立唱片公司的內容。

傳統版多租戶架構

設計多租戶架構的傳統方式是為每個客戶建立個別的資料庫。在此範例中,每個資料庫都會具備自己的 Singers 資料表:

資料庫 1:Ackworth 唱片
SingerId FirstName LastName
1MarcRichards
2CatalinaSmith
資料庫 2:Cama 唱片
SingerId FirstName LastName
1AliceTrentor
2GabrielWright
資料庫 3:Eagan 唱片
SingerId FirstName LastName
1BenjaminMartinez
2HannahHarris

結構定義管理的多用戶群

如要在 Spanner 中設計多租戶架構,另一種方法是讓所有客戶都位於單一資料庫的單一資料表中,並為每位客戶使用不同的主鍵值。舉例來說,您可以在資料表中加入 CustomerId 鍵欄。如果您將 CustomerId 設為第一個索引鍵資料欄,則每個客戶的資料都能獲得良好的本地性。接著,Spanner 就能有效運用資料庫分割功能,根據資料大小和負載模式盡可能提高效能。在下例中,所有客戶都有一個 Singers 資料表:

Spanner 多租戶架構資料庫
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
21AliceTrentor
22GabrielWright
31BenjaminMartinez
32HannahHarris

如果每個租戶都要有個別的資料庫,則請務必注意下列限制:

  • 每個執行個體的資料庫數量,以及每個資料庫的資料表和索引數量均有限制。視客戶數量而定,可能無法建立個別的資料庫或資料表。
  • 新增資料表和非交錯索引可能會花很多時間才能完成。如果結構定義設計需要新增資料表和索引,您可能無法獲得需要的效能。

如要建立個別的資料庫,則透過此方式將資料表分散到各資料庫,讓每個資料庫 每週進行較少次結構定義變更,成功的機率較大。

當您為應用程式的每位客戶建立個別資料表和索引時,請勿將全部的資料表和索引放置到相同的資料庫。請將資料表和索引拆分到許多資料庫上,以降低建立大量索引所造成的效能問題

如要進一步瞭解其他資料管理模式和多租用戶應用程式設計,請參閱「在 Spanner 中實作多租用戶