Panoramica degli schemi

Questa pagina illustra i requisiti dello schema di Spanner, come utilizzarlo per creare relazioni gerarchiche e le funzionalità dello schema. Inoltre, introduce le tabelle con interleaving, che possono migliorare le prestazioni delle query quando esegui query sulle tabelle in una relazione padre-figlio.

Uno schema è uno spazio dei nomi che contiene oggetti di database, come tabelle, viste, indici e funzioni. Utilizzi gli schemi per organizzare gli oggetti, applicare i privilegi di controllo dell'accesso granulare ed evitare collisioni dei nomi. Devi definire uno schema per ogni database in Spanner.

Puoi anche segmentare ulteriormente e archiviare le righe nella tabella del database in diverse regioni geografiche. Per ulteriori informazioni, consulta la panoramica del partizionamento geografico.

Dati fortemente tipizzati

I dati in Spanner sono fortemente tipizzati. I tipi di dati includono tipi scalari e complessi, descritti in Tipi di dati in GoogleSQL e Tipi di dati PostgreSQL.

Scegli una chiave principale

I database Spanner possono contenere una o più tabelle. Le tabelle sono strutturate come righe e colonne. Lo schema della tabella definisce una o più colonne della tabella come chiave primaria della tabella, che identifica in modo univoco ogni riga. Le chiavi principali sono sempre indicizzate per la ricerca rapida delle righe. Se vuoi aggiornare o eliminare righe esistenti in una tabella, la tabella deve avere una chiave primaria. Una tabella senza colonne di chiave primaria può avere una sola riga. Solo i database in dialetto GoogleSQL possono avere tabelle senza una chiave primaria.

Spesso la tua applicazione ha già un campo ideale per l'utilizzo come chiave primaria. Ad esempio, per una tabella Customers potrebbe essere presente un CustomerId fornito dall'applicazione che funge da chiave primaria. In altri casi, potrebbe essere necessario generare una chiave primaria durante l'inserimento della riga. In genere si tratta di un valore intero univoco senza significato commerciale (una chiave primaria surrogata).

In ogni caso, devi fare attenzione a non creare hot spot con la scelta della chiave primaria. Ad esempio, se inserisci record con un numero intero in aumento monotonico come chiave, lo inserirai sempre alla fine dello spazio della chiave. Questo non è auspicabile perché Spanner suddivide i dati tra i server in base agli intervalli di chiavi, il che significa che gli inserimenti verranno indirizzati a un singolo server, creando un hotspot. Esistono tecniche che possono distribuire il carico su più server ed evitare hotspot:

Relazioni tra tabelle padre e figlio

Esistono due modi per definire le relazioni padre-figlio in Spanner: interfoliazione delle tabelle e chiavi esterne.

L'interleaving delle tabelle di Spanner è una buona scelta per molte relazioni padre-figlio. Con l'interlacciamento, Spanner colloca fisicamente le righe secondarie con le righe principali nello spazio di archiviazione. La co-location può migliorare notevolmente le prestazioni. Ad esempio, se hai una tabella Customers e una tabella Invoices e la tua applicazione recupera spesso tutte le fatture di un cliente, puoi definire Invoices come una tabella secondaria interlacciata di Customers. In questo modo dichiari una relazione di località dei dati tra due tabelle indipendenti. Stai dicendo a Spanner di memorizzare una o più righe di Invoices con una riga Customers.

Associa una tabella figlio a una tabella principale utilizzando DDL che dichiara la tabella figlio come interlacciata nella tabella principale e includendo la chiave primaria della tabella principale come prima parte della chiave primaria composta della tabella figlio. Per ulteriori informazioni sull'interleaving, consulta la sezione Creare tabelle con interleaving più avanti in questa pagina.

Le chiavi esterne sono una soluzione padre-figlio più generica e sono adatte a ulteriori casi d'uso. Non sono limitate alle colonne di chiave primaria e le tabelle possono avere più relazioni di chiave esterna, sia come tabella principale in alcune relazioni sia come tabella figlio in altre. Tuttavia, una relazione di chiave esterna non implica la collocazione delle tabelle nel livello di archiviazione.

Google consiglia di scegliere di rappresentare le relazioni padre-figlio come tabelle con interleaving o come chiavi esterne, ma non entrambe. Per ulteriori informazioni sulle chiavi esterne e sul loro confronto con le tabelle con interleaving, consulta la Panoramica delle chiavi esterne.

Chiavi primarie nelle tabelle con interfoliazione

Per l'interlacciamento, ogni tabella deve avere una chiave primaria. Se dichiari una tabella come figlia interleaved di un'altra, la tabella deve avere una chiave primaria composta che includa tutti i componenti della chiave primaria della tabella principale, nello stesso ordine, e, in genere, una o più colonne aggiuntive della tabella figlio.

Spanner memorizza le righe in ordine alfabetico in base ai valori della chiave primaria, con le righe figlio inserite tra le righe principali. Visualizza un'illustrazione delle righe con interfoliazione in Creare tabelle con interfoliazione più avanti in questa pagina.

In sintesi, Spanner può collocare fisicamente le righe di tabelle correlate. Gli esempi di schema mostrano l'aspetto di questo layout fisico.

Suddivisioni del database

Puoi definire gerarchie di relazioni padre-figlio con interleaving fino a sette livelli di profondità, il che significa che puoi collocare in modo co-localizzato le righe di sette tabelle indipendenti. Se le dimensioni dei dati nelle tabelle sono ridotte, probabilmente un singolo server Spanner può gestire il tuo database. Ma cosa succede quando le tabelle correlate crescono e iniziano a raggiungere i limiti di risorse di un singolo server? Spanner è un database distribuito, il che significa che, man mano che il database cresce, suddivide i dati in blocchi chiamati "split". I singoli split possono spostarsi indipendentemente l'uno dall'altro e essere assegnati a server diversi, che possono trovarsi in località fisiche diverse. Una suddivisione contiene un intervallo di righe contigue. Le chiavi di inizio e fine di questo intervallo sono chiamate "confini della suddivisione". Spanner aggiunge e rimuove automaticamente i confini della suddivisione in base alle dimensioni e al carico, modificando il numero di suddivisioni nel database.

Suddivisione in base al carico

Come esempio di come Spanner esegue la suddivisione in base al carico per mitigare gli hotspot di lettura, supponiamo che il tuo database contenga una tabella con 10 righe che vengono lette più di frequente rispetto a tutte le altre righe della tabella. Spanner può aggiungere confini della suddivisione tra ciascuna di queste 10 righe in modo che ciascuna venga gestita da un server diverso, anziché consentire a tutte le letture di queste righe di consumare le risorse di un singolo server.

Come regola generale, se segui le best practice per la progettazione dello schema, Spanner può mitigare gli hotspot in modo che il throughput di lettura deve migliorare ogni pochi minuti fino a saturare le risorse nell'istanza o incorrere in casi in cui non è possibile aggiungere nuovi confini della suddivisione (in quanto hai una suddivisione che copre solo una riga senza elementi secondari interlacciati).

Schemi denominati

Gli schemi con nome ti consentono di organizzare insieme i dati simili. In questo modo, puoi trovare rapidamente gli oggetti nella console Google Cloud, applicare i privilegi ed evitare collisioni di nomi.

Gli schemi denominati, come altri oggetti del database, vengono gestiti utilizzando DDL.

Gli schemi denominati di Spanner ti consentono di utilizzare nomi completi (FQN) per eseguire query sui dati. I DN completi ti consentono di combinare il nome dello schema e il nome dell'oggetto per identificare gli oggetti del database. Ad esempio, puoi creare uno schema chiamato warehouse per l'unità commerciale del magazzino. Le tabelle che utilizzano questo schema possono includere: product, order e customer information. In alternativa, puoi creare uno schema denominato fulfillment per l'unità commerciale di evasione degli ordini. Questo schema potrebbe anche avere tabelle denominate product, order e customer information. Nel primo esempio, il nome di dominio completo è warehouse.product e nel secondo esempio è fulfillment.product. In questo modo si evitano confusioni nelle situazioni in cui più oggetti condividono lo stesso nome.

Nel DDL CREATE SCHEMA, agli oggetti tabella viene assegnato sia un nome completo, ad esempio sales.customers, sia un nome breve, ad esempio sales.

I seguenti oggetti database supportano gli schemi denominati:

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

Per ulteriori informazioni sull'utilizzo degli schemi denominati, consulta Gestire gli schemi denominati.

Utilizzare controllo dell'accesso granulare con schemi denominati

Gli schemi con nome ti consentono di concedere l'accesso a livello di schema a ogni oggetto dello schema. Questo vale per gli oggetti dello schema esistenti al momento in cui concedi l'accesso. Devi concedere l'accesso agli oggetti aggiunti in un secondo momento.

Controllo dell'accesso granulare limita l'accesso a interi gruppi di oggetti di database, come tabelle, colonne e righe della tabella.

Per ulteriori informazioni, vedi Concedere i privilegi di controllo dell'accesso granulare agli schemi nominativi.

Esempi di schemi

Gli esempi di schema in questa sezione mostrano come creare tabelle principali e secondarie con e senza interlacciamento e illustrano i layout fisici corrispondenti dei dati.

Crea una tabella principale

Supponiamo che tu stia creando un'applicazione musicale e che tu abbia bisogno di una tabella che memorizzi righe di dati sui cantanti:

Tabella Cantanti con cinque righe e quattro colonne

Tieni presente che la tabella contiene una colonna della chiave primaria, SingerId, che appare a sinistra della riga in grassetto e che le tabelle sono organizzate in righe e colonne.

Puoi definire la tabella con il seguente DDL:

GoogleSQL

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

PostgreSQL

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

Tieni presente quanto segue sullo schema di esempio:

  • Singers è una tabella alla radice della gerarchia del database (in quanto non è definita come tabella secondaria con interfoliazione di un'altra tabella).
  • Per i database in dialetto GoogleSQL, le colonne della chiave primaria sono in genere annotate con NOT NULL (anche se puoi omettere questa annotazione se vuoi consentire valori NULL nelle colonne chiave. Per ulteriori informazioni, consulta Colonne chiave.
  • Le colonne non incluse nella chiave primaria sono chiamate colonne non chiave e possono avere un'annotazione facoltativa NOT NULL.
  • Le colonne che utilizzano il tipo STRING o BYTES in GoogleSQL devono essere definite con una lunghezza, che rappresenta il numero massimo di caratteri Unicode che possono essere memorizzati nel campo. La specifica della lunghezza è facoltativa per i tipi varchar e character varying di PostgreSQL. Per ulteriori informazioni, consulta Tipi di dati scalari per i database in dialetto GoogleSQL e Tipi di dati PostgreSQL per i database in dialetto PostgreSQL.

Qual è il layout fisico delle righe nella tabella Singers? Il diagramma seguente mostra le righe della tabella Singers memorizzate in base alla chiave primaria ("Cantanti(1)" e poi "Cantanti(2)", dove il numero tra parentesi è il valore della chiave primaria.

Righe di esempio di una tabella archiviata in ordine di chiave primaria

Il diagramma precedente mostra un esempio di confine di suddivisione tra le righe con chiave Singers(3) e Singers(4), con i dati delle suddivisioni risultanti assegnati a server diversi. Man mano che questa tabella cresce, è possibile che le righe di dati Singers vengano archiviate in posizioni diverse.

Creare tabelle principali e secondarie

Supponiamo che tu voglia aggiungere alcuni dati di base sugli album di ciascun cantante all'applicazione musicale.

Tabella Album con cinque righe e tre colonne

Tieni presente che la chiave primaria di Albums è composta da due colonne: SingerId e AlbumId, per associare ogni album al relativo cantante. Lo schema di esempio riportato di seguito definisce le tabelle Albums e Singers nella radice della gerarchia del database, rendendole tabelle sorelle.

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

GoogleSQL

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

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

Il layout fisico delle righe di Singers e Albums è simile al seguente diagramma, con le righe della tabella Albums archiviate per chiave primaria contigüe, quindi le righe di Singers archiviate per chiave primaria contigüe:

Layout fisico delle righe

Una nota importante sullo schema è che Spanner non presuppone relazioni di località dei dati tra le tabelle Singers e Albums, perché sono tabelle di primo livello. Man mano che il database cresce, Spanner può aggiungere confini della suddivisione tra le righe. Ciò significa che le righe della tabella Albums potrebbero finire in una suddivisione diversa rispetto alle righe della tabella Singers, e le due suddivisioni potrebbero spostarsi indipendentemente l'una dall'altra.

A seconda delle esigenze dell'applicazione, potrebbe essere sufficiente consentire ai dati di Albums di essere collocati in suddivisioni diverse rispetto ai dati di Singers. Tuttavia, ciò potrebbe comportare un calo delle prestazioni a causa della necessità di coordinare letture e aggiornamenti tra risorse distinte. Se la tua applicazione deve recuperare spesso informazioni su tutti gli album di un determinato cantante, devi creare Albums come tabella figlio interlacciata di Singers, che colloca le righe delle due tabelle lungo la dimensione della chiave primaria. L'esempio seguente lo spiega in maggiore dettaglio.

Creare tabelle con interfoliazione

Una tabella con interfoliazione è una tabella che dichiari come figlia con interfoliazione di un'altra tabella perché vuoi che le righe della tabella figlio vengano memorizzate fisicamente con la riga principale associata. Come accennato in precedenza, la chiave primaria della tabella padre deve essere la prima parte della chiave primaria composita della tabella figlio.

Una volta interlizzata, una tabella è definitiva. Non puoi annullare l'interlacciamento. Devi invece creare di nuovo la tabella ed eseguire la migrazione dei dati al suo interno.

Durante la progettazione dell'applicazione musicale, supponi di capire che l'app deve accedere spesso alle righe della tabella Albums quando accede a una riga Singers. Ad esempio, quando accedi alla riga Singers(1), devi anche accedere alle righe Albums(1, 1) e Albums(1, 2). In questo caso, Singers e Albums devono avere una relazione di località dei dati molto stretta. Puoi dichiarare questa relazione di località dei dati creando Albums come tabella secondaria interlacciata di Singers.

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

La riga in grassetto nello schema seguente mostra come creare Albums come tabella interlacciata di Singers.

GoogleSQL

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

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;

Note su questo schema:

  • SingerId, che è la prima parte della chiave primaria della tabella figlio Albums, è anche la chiave primaria della tabella padre Singers.
  • L'annotazione ON DELETE CASCADE indica che quando viene eliminata una riga della tabella principale, vengono eliminate automaticamente anche le righe figlie. Se una tabella figlio non ha questa annotazione o se l'annotazione è ON DELETE NO ACTION, devi eliminare le righe secondarie prima di poter eliminare la riga principale.
  • Le righe interlacciate vengono ordinate prima in base alle righe della tabella principale e poi in base alle righe contigue della tabella figlio che condividono la chiave primaria della tabella principale. Ad esempio, "Cantanti(1)", "Album(1, 1)" e "Album(1, 2)".
  • La relazione di località dei dati di ogni cantante e dei relativi album viene conservata se questo database viene suddiviso, a condizione che le dimensioni di una riga Singers e di tutte le sue righe Albums rimangano al di sotto del limite di dimensioni della suddivisione e che non esistano hotspot in nessuna di queste righe Albums.
  • La riga principale deve esistere prima di poter inserire le righe secondarie. La riga principale può essere già presente nel database o può essere inserita prima dell'inserimento delle righe secondarie nella stessa transazione.

Le righe degli album sono interlacciate tra le righe dei cantanti

Crea una gerarchia di tabelle con interfoliazione

La relazione padre-figlio tra Singers e Albums può essere estesa a più tabelle discendenti. Ad esempio, puoi creare una tabella interlacciata chiamata Songs come elemento secondario di Albums per memorizzare l'elenco tracce di ogni album:

Tabella dei brani con sei righe e quattro colonne

Songs deve avere una chiave primaria che includa tutte le chiavi primarie delle tabelle situate a un livello superiore nella gerarchia, ovvero SingerId e 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,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

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;

Il seguente diagramma rappresenta una vista fisica delle righe interlacciate.

I brani sono interlacciati negli album, che sono interlacciati tra i cantanti

In questo esempio, con l'aumentare del numero di cantanti, Spanner aggiunge confini di suddivisione tra i cantanti per preservare la localizzazione dei dati tra un cantante e i dati dei suoi album e dei suoi brani. Tuttavia, se le dimensioni di una riga del cantante e delle relative righe figlio superano il limite di dimensioni della suddivisione o se viene rilevato un hotspot nelle righe figlio, Spanner tenta di aggiungere confini della suddivisione per isolare la riga dell'hotspot insieme a tutte le righe figlio sottostanti.

In sintesi, una tabella principale, insieme a tutte le relative tabelle figlio e discendenti, forma una gerarchia di tabelle nello schema. Sebbene ogni tabella della gerarchia sia indipendente dal punto di vista logico, interleavingle fisicamente in questo modo può migliorare le prestazioni, pre-unire efficacemente le tabelle e consentire di accedere contemporaneamente alle righe correlate riducendo al minimo gli accessi allo spazio di archiviazione.

Join con tabelle con interfoliazione

Se possibile, unisci i dati nelle tabelle interlacciate in base alla chiave primaria. Poiché in genere ogni riga interlacciata viene memorizzata fisicamente nella stessa suddivisione della riga principale, Spanner può eseguire join per chiave primaria localmente, riducendo al minimo l'accesso allo spazio di archiviazione e il traffico di rete. Nell'esempio seguente, Singers e Albums sono uniti sulla chiave primaria 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;

Colonne chiave

Questa sezione include alcune note sulle colonne chiave.

Modificare le chiavi delle tabelle

Le chiavi di una tabella non possono essere modificate. Non puoi aggiungere una colonna della chiave a una tabella esistente o rimuoverla da una tabella esistente.

Memorizzare valori NULL in una chiave primaria

In GoogleSQL, se vuoi memorizzare NULL in una colonna della chiave primaria, ometti la clausola NOT NULL per quella colonna nello schema. I database in dialetto PostgreSQL non supportano i valori NULL in una colonna della chiave primaria.

Ecco un esempio di omissione della clausola NOT NULL nella colonna della chiave primaria SingerId. Tieni presente che, poiché SingerId è la chiave primaria, in quella colonna può esserci solo una riga che memorizza SingerId.NULL

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

La proprietà nullable della colonna della chiave primaria deve corrispondere tra le dichiarazioni della tabella padre e della tabella figlio. In questo esempio, NOT NULL per la colonna Albums.SingerId non è consentito perché Singers.SingerId lo omette.

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

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;

Tipi non consentiti

Le seguenti colonne non possono essere di tipo ARRAY:

  • Le colonne chiave di una tabella.
  • Le colonne chiave di un indice.

Progettare per il multitenancy

Ti consigliamo di implementare il multitenancy se archivi dati appartenenti a diversi clienti. Ad esempio, un servizio di musica potrebbe voler archiviare separatamente i contenuti di ogni singola casa discografica.

Multitenancy classico

Il modo classico per progettare per il multitenancy è creare un database separato per ogni cliente. In questo esempio, ogni database ha la propria tabella Singers:

Database 1: Ackworth Records
SingerId Nome Cognome
1MarcRichards
2CatalinaSmith
Database 2: Cama Records
SingerId Nome Cognome
1AliceTrentor
2GabrielWright
Database 3: Eagan Records
SingerId Nome Cognome
1BenjaminMartinez
2HannahHarris

Multitenancy gestita tramite schema

Un altro modo per progettare il multitenancy in Spanner è avere tutti i clienti in un'unica tabella in un unico database e utilizzare un valore della chiave primaria diverso per ogni cliente. Ad esempio, puoi includere una colonna chiave CustomerId nelle tabelle. Se imposti CustomerId come prima colonna della chiave, i dati di ciascun cliente hanno una buona localizzazione. Spanner può quindi utilizzare in modo efficace le suddivisioni del database per massimizzare le prestazioni in base alle dimensioni dei dati e ai pattern di caricamento. Nell'esempio seguente, esiste una singola tabella Singers per tutti i clienti:

Database multi-tenancy Spanner
CustomerId SingerId Nome Cognome
11MarcRichards
12CatalinaSmith
21AliceTrentor
22GabrielWright
31BenjaminMartinez
32HannahHarris

Se devi avere database separati per ogni tenant, tieni presente i seguenti vincoli:

  • Esistono limiti per il numero di database per istanza e per il numero di tabelle e indici per database. A seconda del numero di clienti, potrebbe non essere possibile avere database o tabelle distinti.
  • L'aggiunta di nuove tabelle e indici non interlacciati può richiedere molto tempo. Potresti non essere in grado di ottenere il rendimento desiderato se la progettazione dello schema dipende dall'aggiunta di nuove tabelle e nuovi indici.

Se vuoi creare database separati, potresti ottenere risultati migliori se suddividi le tabelle nei database in modo che ogni database abbia un numero ridotto di modifiche dello schema a settimana.

Se crei tabelle e indici separati per ogni cliente della tua applicazione, non inserire tutte le tabelle e gli indici nello stesso database. Suddividili su più database per ridurre i problemi di prestazioni legati alla creazione di un numero elevato di indici.

Per scoprire di più su altri pattern di gestione dei dati e sul design delle applicazioni per il multitenancy, consulta Implementazione del multitenancy in Spanner.