本頁面討論 Spanner 結構定義規定、如何使用結構定義建立階層式關係,以及結構定義功能。此外,還推出交錯式資料表,查詢具有上層/下層關係的資料表時,可提高查詢效能。
結構定義是包含資料庫物件 (例如資料表、檢視區塊、索引和函式) 的命名空間。您可以使用結構定義來整理物件、套用精細的存取權控管權限,以及避免命名衝突。您必須為 Spanner 中的每個資料庫定義結構定義。
您也能為不同地理區域的資料庫資料表,進一步區隔及儲存資料列。詳情請參閱地理位置分割總覽。
嚴格型別資料
Spanner 中的資料是強型別。資料類型包括純量和複雜類型,詳情請參閱「GoogleSQL 中的資料類型」和「PostgreSQL 資料類型」。
選擇主要金鑰
Spanner 資料庫可包含一或多個資料表。表格的結構為資料列和資料欄。資料表結構定義一或多個資料表欄做為資料表的主鍵,用來唯一識別每個資料列。主鍵一律會建立索引,方便快速查詢資料列。如要更新或刪除資料表中的現有資料列,則該資料表必須有主鍵。沒有主鍵資料欄的資料表只能擁有一個資料列。只有 GoogleSQL 方言資料庫可以有不含主鍵的資料表。
您的應用程式通常已有非常適合當做主鍵使用的欄位。舉例來說,對於 Customers 資料表,應用程式可能已提供非常適合當主鍵的 CustomerId。在其他情況下,您可能需要在插入資料列時產生主鍵。這通常是沒有業務意義的唯一整數值 (替代主鍵)。
在所有情況下,您都應該要小心,避免因為選錯主鍵而發生資源使用率不均的情況。舉例來說,如果您插入的記錄是以單調遞增整數做為索引鍵,則一律會在索引鍵空間的尾端插入資料。這不是一個好的做法,因為 Spanner 會依據索引鍵範圍將資料分配到各伺服器,也就是說,您插入的資料會被引導至單一伺服器,而導致資源使用率不均。您可善用下列技術,將負載分散到多部伺服器上,以避免發生資源使用率不均的情形。
- 雜湊處理索引鍵,並儲存至資料欄。使用雜湊資料欄 (或同時使用雜湊資料欄和唯一鍵資料欄) 做為主鍵。
- 在主鍵中交換資料欄的順序。
- 使用通用唯一識別碼 (UUID)。建議使用第 4 版的 UUID,因為此版本在高階位元中使用隨機值。請勿使用將時間戳記儲存在高階位元的 UUID 演算法 (例如第 1 版 UUID)。
- 位元反轉序列值。
父項/子項資料表關係
在 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 的結構定義。使用此結構定義的資料表可能包括:product、order 和 customer information。或者,您也可以為履行業務單位建立名為 fulfillment 的結構定義。這個結構定義也可能包含名為 product、order 和 customer
information 的資料表。在第一個範例中,FQN 為 warehouse.product,在第二個範例中,FQN 為 fulfillment.product。避免多個物件共用相同名稱時發生混淆。
在 CREATE SCHEMA DDL 中,資料表物件會同時獲得 FQN (例如 sales.customers) 和簡短名稱 (例如 sales)。
下列資料庫物件支援具名結構定義:
TABLECREATEINTERLEAVE IN [PARENT]FOREIGN KEYSYNONYM
VIEWINDEXFOREIGN KEYSEQUENCE
如要進一步瞭解如何使用具名結構定義,請參閱「管理具名結構定義」。
使用精細的存取權控管機制和具名結構定義
具名結構定義可讓您授予結構定義層級的存取權給結構定義中的每個物件。這項設定適用於您授予存取權時存在的結構定義物件。 你必須授予後續新增物件的存取權。
精細的存取權控管機制會限制對整組資料庫物件的存取權,例如資料表、資料欄和資料列。
詳情請參閱「授予具名結構定義精細的存取權控管權限」。
結構定義範例
本節的結構定義範例顯示如何建立包含及不包含交錯的父項和子項資料表,並且說明資料的對應實體配置。
建立父項資料表
假設您正在建立音樂應用程式,您需要一個資料表來儲存歌手資料的資料列:
請注意,該資料表包含一個主鍵資料列「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 中,採用
STRING或BYTES類型的資料欄必須以長度來定義,此長度代表欄位中可儲存的 Unicode 字元上限。PostgreSQLvarchar和character varying類型可選擇是否指定長度。詳情請參閱 GoogleSQL 方言資料庫的純量資料類型,以及 PostgreSQL 方言資料庫的 PostgreSQL 資料類型。
Singers 資料表中的資料列實體配置看起來會是什麼樣子?下圖顯示依據主鍵儲存的 Singers 資料表資料列 (「Singers(1)」和「Singers(2)」,其中括號中的數字是主鍵值)。
上圖說明鍵值為 Singers(3) 和 Singers(4) 的資料列之間的分割界線範例,將分割後的資料指派給不同的伺服器。當此資料表增長時,即可將 Singers 資料的資料列儲存於不同的位置。
建立父項和子項資料表
假設您現在要將每位歌手的專輯基本資料新增至音樂應用程式。
請注意,Albums 的主鍵是由 SingerId 和 AlbumId 兩個資料欄組成,以便建立專輯和歌手之間的關聯。下列結構定義範例會在資料庫階層根部定義 Albums 和 Singers 資料表,讓這兩個資料表變成同層級資料表。
-- 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) );
Singers 和 Albums 的資料列實體配置看起來如下圖,其中有由連續主鍵儲存的 Albums 資料表資料列,然後是由連續主鍵儲存的 Singers 資料列:
上述結構定義的重要注意事項之一,即是 Singers 和 Albums 均為頂層資料表,因此 Spanner 假設這兩者之間沒有資料本地性。當資料庫變大時,Spanner 即可在任何資料列之間新增分割界線。這表示 Albums 資料表的資料列的分割結果可能和 Singers 資料表的資料列不同,而且這兩個分割可獨立移動。
您可視應用程式的需求,將 Albums 資料放在與 Singers 資料不同的分割上。不過,由於需要協調不同資源之間的讀取和更新作業,這可能會導致效能降低。如果應用程式常常需要擷取特定歌手所有專輯的相關資訊,那麼您應該建立 Albums 當做 Singers 的交錯子項資料表,如此即可在主鍵維度將這兩個資料表的資料列放置在相同位置。下一個範例會更詳細地說明這種做法。
建立交錯式資料表
交錯式資料表是指您宣告為其他資料表交錯子項的資料表,因為您想將子項資料表的資料列與相關父項資料列儲存在一起。如先前所述,父項資料表主鍵必須是子項資料表複合式主鍵的第一部分。
交錯處理資料表後,這項作業就無法復原。交錯處理後無法復原。 您必須重新建立資料表,然後將資料遷移至該資料表。
假設您在設計音樂應用程式時發現,應用程式存取 Singers 資料列時,需要經常存取 Albums 資料表中的資料列。舉例來說,當您存取 Singers(1) 列時,也需要存取 Albums(1, 1) 和 Albums(1, 2) 列。在這種情況下,Singers 和 Albums 必須有密切的資料本地性。您可以建立 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資料列中沒有任何熱點。 - 父項資料列必須存在,您才能插入子項資料列。父項資料列可能已經存在於資料庫中,或者在稍早新增資料列到子項資料表的相同交易中新增。
假設您想將 Projects 和 Resources 建模為交錯資料表,在某些情況下,INTERLEAVE IN 可能會很有幫助,例如實體不需要 Projects 列存在,就能存在於該列下方 (假設專案已刪除,但必須先清除資源,才能刪除專案)。
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 列。
建立交錯資料表的階層
Singers 和 Albums 之間的父項/子項關係可延伸至更多下階資料表。比方說,您可以建立名為 Songs 的交錯資料表當做 Albums 的子項,以儲存每張專輯的歌曲清單:
Songs 的主鍵必須包含階層中較高層級資料表的所有主鍵,即 SingerId 和 AlbumId。
-- 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;
下圖代表交錯資料列的實體檢視畫面。
在本例中,隨著歌手人數增加,Spanner 會在歌手之間新增分割界線,以保留歌手及其專輯和歌曲資料之間的資料本地性。不過,如果歌手資料列及其子項資料列的大小超過分割大小限制,或系統在子項資料列中偵測到熱點,Spanner 會嘗試新增分割界線,以隔離該熱點資料列及其下方的所有子項資料列。
簡而言之,父項資料表及其所有子項和下階資料表在結構定義中構成資料表階層。雖然階層中每個資料表在邏輯上都是獨立的,但透過這種方式進行實體交錯,可提升效能、有效地預先彙整資料表、讓您一併存取相關資料列,同時減少儲存空間存取次數。
彙整交錯式資料表
可能的話,利用主鍵將資料彙整於交錯的資料表中。由於每個交錯資料列通常會與父項資料列儲存在相同的分割中,因此 Spanner 可在本機執行主鍵聯結,減少儲存空間存取次數並降低網路流量。在下列範例中,Singers 和 Albums 是在 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 TABLEDDL 陳述式為指定資料欄設定區域性群組,或使用ALTER TABLEDDL 陳述式變更資料表資料欄使用的區域性群組。DDL 陳述式會決定儲存在區域性群組中的資料欄。最後,您能更有效率地讀取這些資料欄中的資料。
索引鍵資料欄
本節包含有關重要資料欄的附註。
變更資料表鍵
資料表的索引鍵無法變更;您無法將索引鍵資料欄新增到現有資料表,或從現有資料表移除索引鍵資料欄。
在主鍵中儲存空值
在 GoogleSQL 中,如要在主鍵資料欄中儲存空值,請在結構定義中省略該資料欄的 NOT NULL 子句。(PostgreSQL 方言資料庫不支援主鍵欄中的 NULL 值)。
下列範例示範如何在主鍵資料欄 NOT NULL 上省略 SingerId 子句。請注意,由於 SingerId 是主鍵,因此最多只能有一個資料列儲存 NULL。
CREATE TABLE Singers ( SingerId INT64 PRIMARY KEY, FirstName STRING(1024), LastName STRING(1024), );
在父項和子項資料表的宣告中,主鍵資料欄的 NULLABLE (可為空值) 屬性必須相符。在本範例中,系統不允許使用 NOT NULL 做為 Albums.SingerId 欄,因為 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 資料表:
| SingerId | FirstName | LastName |
|---|---|---|
| 1 | Marc | Richards |
| 2 | Catalina | Smith |
| SingerId | FirstName | LastName |
|---|---|---|
| 1 | Alice | Trentor |
| 2 | Gabriel | Wright |
| SingerId | FirstName | LastName |
|---|---|---|
| 1 | Benjamin | Martinez |
| 2 | Hannah | Harris |
架構管理的多用戶群
在 Spanner 中設計多租戶架構的另一種方式,是將所有客戶放在單一資料庫的單一資料表中,並為每個客戶使用不同的主鍵值。舉例來說,您可以在表格中加入 CustomerId 鍵欄。如果您將 CustomerId 設為第一個索引鍵資料欄,則每個顧客的資料都能獲得良好的本地性。Spanner 接著就能有效運用資料庫分割,根據資料大小和負載模式,盡可能提升效能。在下列範例中,所有客戶都有一個 Singers 資料表:
| CustomerId | SingerId | FirstName | LastName |
|---|---|---|---|
| 1 | 1 | Marc | Richards |
| 1 | 2 | Catalina | Smith |
| 2 | 1 | Alice | Trentor |
| 2 | 2 | Gabriel | Wright |
| 3 | 1 | Benjamin | Martinez |
| 3 | 2 | Hannah | Harris |
如果每個租戶都要有個別的資料庫,則請務必注意下列限制:
- 每個執行個體的資料庫數量,以及每個資料庫的資料表和索引數量均有限制。視客戶數量而定,可能無法建立個別的資料庫或資料表。
- 新增資料表和非交錯索引可能會花很多時間。如果結構定義設計需要新增資料表和索引,您可能無法獲得需要的效能。
如要建立個別的資料庫,則透過此方式將資料表分散到各資料庫,讓每個資料庫 每週進行較少次結構定義變更,成功的機率較大。
當您為應用程式的每位客戶建立個別資料表和索引時,請勿將全部的資料表和索引放置到相同的資料庫。請將資料表和索引拆分到許多資料庫上,以降低建立大量索引所造成的效能問題。
如要進一步瞭解其他資料管理模式和多租戶應用程式設計,請參閱「在 Spanner 中實作多租戶」。