Cette page a été traduite par l'API Cloud Translation.
Switch to English

Schéma et modèle de données

Récapitulatif de modèle de données

Une base de données Cloud Spanner peut contenir une ou plusieurs tables. Les tables ressemblent à des tables de base de données relationnelle du fait qu'elles sont structurées avec des lignes, des colonnes et des valeurs, et qu'elles contiennent des clés primaires. Les données dans Cloud Spanner sont fortement typées : vous devez définir un schéma pour chaque base de données, et ce schéma doit spécifier les types de données de chaque colonne de chaque table. Les types de données autorisés incluent les données scalaires et de tableaux, qui sont expliqués plus en détail sur la page Types de données. Vous pouvez également définir un ou plusieurs index secondaires sur une table.

Relations de table parents-enfants

Il existe deux façons de définir des relations parents-enfants dans Cloud Spanner : l'entrelacement des tables et les clés étrangères.

L'entrelacement des tables de Cloud Spanner est un bon choix pour les relations parents-enfants dans lesquelles la clé primaire de la table enfant inclut les colonnes de clé primaire de la table parente. La colocation des lignes enfants avec leurs lignes parentes peut améliorer considérablement les performances. Par exemple, s'il existe une table Customers et une table Invoices, et que l'application récupère fréquemment toutes les factures d'un client donné, vous pouvez définir Invoices en tant que table enfant de la table Customers. Vous déclarez ainsi une relation de localité de données entre deux tables logiquement indépendantes et indiquez à Cloud Spanner de stocker physiquement une ou plusieurs lignes de la table Invoices avec une ligne de la table Customers.

Pour en savoir plus sur l'entrelacement, consultez la section Créer des tables entrelacées ci-dessous.

Les clés étrangères constituent une solution parent-enfant plus générale et répondent à des cas d'utilisation supplémentaires. Elles ne sont pas limitées aux colonnes de clé primaire, et les tables peuvent posséder plusieurs relations de clés étrangères en faisant office de tables parentes dans certaines relations et de tables enfants dans d'autres. Toutefois, une relation de clé étrangère n'implique pas la colocation des tables dans la couche de stockage.

Pour plus d'informations sur les clés étrangères et leur comparaison avec les tables entrelacées, consultez la section Présentation des clés étrangères.

Clés primaires

Pour indiquer à Cloud Spanner quelles lignes de la table Invoices stocker avec quelles lignes de la table Customers, utilisez la clé primaire de ces tables. Chaque table doit disposer d'une clé primaire pouvant être composée de zéro colonne ou plus de cette table. Si vous déclarez qu'une table est l'enfant d'une autre, les colonnes de clé primaire de la table parent doivent être le préfixe de la clé primaire de la table enfant. De la sorte, si la clé primaire d'une table parent est composée d'un nombre N de colonnes, la clé primaire de chacune de ses tables enfants doit également être composée du même nombre N de colonnes, dans le même ordre et commençant par la même colonne.

Cloud Spanner stocke les lignes dans l'ordre de tri des valeurs de clé primaire, les lignes enfants étant insérées entre les lignes parents qui partagent le même préfixe de clé primaire. L'insertion de lignes enfants entre les lignes parents en fonction de la dimension de la clé primaire est appelée entrelacement et les tables enfants sont appelées tables entrelacées. (Pour un exemple de lignes entrelacées, consultez la section Créer des tables entrelacées ci-dessous.)

En résumé, Cloud Spanner peut colocaliser physiquement des lignes de tables associées. Les exemples de schéma ci-dessous montrent à quoi ressemble la disposition physique résultante.

Choisir une clé primaire

La clé primaire identifie de manière unique chaque ligne d'une table. Si vous souhaitez mettre à jour ou supprimer les lignes existantes d'une table, celle-ci doit disposer d'une clé primaire composée d'une ou de plusieurs colonnes. (Une table sans colonne de clé primaire ne peut contenir qu'une seule ligne.) Souvent, votre application possède déjà un champ qui peut parfaitement remplir la fonction de clé primaire. Dans l'exemple de table Customers ci-dessus, cela pourrait être un champ CustomerId fourni par l'application. Dans d'autres cas, vous devrez peut-être générer une clé primaire lors de l'insertion de la ligne, comme une valeur INT64 unique que vous générez.

Dans tous les cas, lors du choix de votre clé primaire, veillez à ne pas créer de hotspots. Par exemple, si vous insérez des données dont la clé est un nombre entier augmentant de manière monotone, les insertions se feront toujours à la fin de l'espace clé. Ce phénomène n'est pas souhaitable, car Cloud Spanner divise les données entre les serveurs par plages de clés, ce qui signifie que les insertions seront dirigées vers un seul serveur, créant ainsi un hotspot. Il existe des techniques pouvant répartir la charge sur plusieurs serveurs et éviter la création de hotspots. Les voici :

  • Hacher la clé et la stocker dans une colonne. Utilisez la colonne de hachage (ou la colonne de hachage et les colonnes de clé unique ensemble) comme clé primaire.
  • Échanger l'ordre des colonnes dans la clé primaire.
  • Utiliser un identifiant unique universel (UUID). La version 4 d'UUID est recommandée, car elle utilise des valeurs aléatoires dans les bits de poids fort. N'utilisez pas d'algorithme UUID (tel que la version 1 d'UUID), car il stocke l'horodatage dans les bits de poids fort.
  • Utiliser des valeurs séquentielles de bits inversés.

Divisions de base de données

Vous pouvez définir des hiérarchies de relations parents-enfants entre des tables allant jusqu'à sept couches, ce qui signifie que vous pouvez colocaliser les lignes de sept tables indépendantes du point de vue logique. Si la taille des données dans vos tables est petite, un seul serveur Cloud Spanner est probablement suffisant pour gérer votre base de données. Mais que se passe-t-il lorsque la taille des tables associées augmente et commence à atteindre les limites de ressources d'un serveur individuel ? Cloud Spanner est une base de données distribuée. Ainsi, à mesure que votre base de données s'agrandit, Cloud Spanner divise vos données en fragments appelés "divisions". Les divisions sont indépendantes les unes des autres et peuvent être affectées à différents serveurs pouvant être situés dans différents emplacements physiques. Une division contient une plage de lignes contigu.s. Les clés de début et de fin de cette plage sont appelées "limites de division". Cloud Spanner ajoute et supprime automatiquement les limites de division en fonction de la taille et/ou de la charge, ce qui modifie le nombre de divisions dans la base de données.

Répartition basée sur la charge

Prenons un exemple de la manière dont Cloud Spanner effectue la répartition basée sur la charge afin de minimiser la création de hotspots de lecture. Supposons que votre base de données contienne une table où 10 lignes sont lues plus fréquemment que toutes les autres. Cloud Spanner peut ajouter des limites de division entre chacune de ces 10 lignes afin qu'elles soient toutes gérées par un serveur différent, plutôt que d'autoriser toutes les lectures de ces lignes à consommer les ressources d'un serveur unique. s'affiche en haut de l'écran.

En règle générale, si vous suivez les bonnes pratiques relatives à la conception de schémas, Cloud Spanner peut atténuer les hotspots, de sorte que le débit de lecture devrait s'améliorer toutes les deux ou trois minutes jusqu'à ce que les ressources de votre instance soient saturées. ou dans les cas où aucune nouvelle limite de division ne peut être ajoutée (car une division ne couvre qu'une seule ligne sans enfants entrelacés).

Exemples de schéma

Les exemples de schéma ci-dessous montrent comment créer des tables Cloud Spanner avec et sans relations parents-enfants, et illustrent la disposition physique correspondante des données.

Créer une table

Supposons que vous créiez une application musicale et que vous ayez besoin d'une table simple (ci-dessous) qui stocke des lignes de données concernant des chanteurs.

Table "Singers" (Chanteurs) comportant 5 lignes et 4 colonnes.

Vue logique des lignes d'une table simple intitulée "Singers" (Chanteurs). La colonne de clé primaire apparaît à gauche de la ligne en gras.

Notez que la table contient une colonne de clé primaire, SingerId, qui apparaît à gauche de la ligne en gras, et que les tables sont organisées en lignes et en colonnes, avec des valeurs.

Vous pouvez définir la table avec un schéma Cloud Spanner comme celui présenté ci-dessous :

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

Veuillez noter ce qui suit à propos de l'exemple de schéma :

  • Singers est une table située à la racine de la hiérarchie de la base de données (car elle n'est pas définie en tant qu'enfant d'une autre table).
  • Les colonnes de clé primaire portent généralement l'annotation NOT NULL (bien que vous puissiez l'omettre si vous souhaitez autoriser les valeurs NULL dans les colonnes de clé ; pour plus d'informations, consultez la section Colonnes de clé).
  • Les colonnes qui ne sont pas incluses dans la clé primaire sont appelées colonnes "non clés" et peuvent comporter l'annotation facultative NOT NULL.
  • Les colonnes qui utilisent le type STRING ou BYTES doivent avoir une longueur définie qui représente le nombre maximal de caractères Unicode pouvant être stockés dans le champ. (Pour plus de détails, consultez la section relative aux types de données scalaires.)

À quoi ressemble la disposition physique des lignes dans la table Singers ? Le diagramme ci-dessous montre les lignes de la table Singers stockées par clé primaire contiguë (c'est-à-dire, par ordre de valeur). Soit : "Singers(1)", puis "Singers(2)", etc. où "Singers(1)" représente la ligne de la table "Singers" associée à 1.

Exemple de lignes d'une table stockée dans l'ordre des clés contiguës.

Disposition physique des lignes de la table "Singers", avec un exemple de limite de division qui résulte en des données gérées par différents serveurs.

Le diagramme ci-dessus illustre un exemple de limite de division entre les lignes appelées Singers(3) et Singers(4). Les données ainsi divisées sont affectées à différents serveurs. Ainsi, lorsque cette table s'agrandit, il est possible que des lignes de données Singers soient stockées à des emplacements différents.

Créer plusieurs tables

Supposons que vous souhaitiez maintenant ajouter des données de base sur les albums de chaque chanteur dans l'application musicale.

Table "Albums" comportant 5 lignes et 3 colonnes

Vue logique des lignes de la table "Albums". Les colonnes de clé primaire apparaissent à gauche de la ligne en gras.

Notez que la clé primaire de la table Albums est composée de deux colonnes : SingerId et AlbumId, pour associer chaque album à son chanteur. L'exemple de schéma suivant définit les tables Albums et Singers à la racine de la hiérarchie de la base de données, ce qui en fait des tables sœurs :

-- Schema hierarchy:
-- + Singers (sibling table of Albums)
-- + Albums (sibling table of Singers)
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);

La disposition physique des lignes des tables Singers et Albums ressemble au diagramme ci-dessous, où les lignes de la table Albums, puis celles de la table Singers, sont stockées par clé primaire contiguë :

Disposition physique des lignes : les lignes des tables "Albums" et "Singers" (Chanteurs) sont chacune stockées par valeur de clé

Disposition physique des lignes des tables "Singers" et "Albums", toutes deux situées à la racine de la hiérarchie de la base de données.

Remarque importante à propos du schéma ci-dessus : Cloud Spanner ne suppose aucune relation de localité de données entre les tables Singers et Albums, car il s'agit de tables racines. Au fur et à mesure que la base de données se développe, Cloud Spanner peut ajouter des limites de division entre toutes les lignes présentées ci-dessus. Ainsi, les lignes de la table Albums peuvent se retrouver dans une division différente de celles de la table Singers, et les deux divisions peuvent exister indépendamment l'une de l'autre.

En fonction des besoins de votre application, il peut s'avérer judicieux de permettre aux données de la table Albums d'être placées dans des divisions différentes de celles où se trouvent les données de la table Singers. Toutefois, si l'application doit fréquemment récupérer des informations sur tous les albums d'un chanteur donné, vous devez créer la table Albums en tant qu'enfant de la table Singers, ce qui colocalise les lignes des deux tables en fonction de la clé primaire. L'exemple suivant explique ce phénomène plus en détail.

Créer des tables entrelacées

Supposons que vous vous rendiez compte, lors de la conception de votre application musicale, que celle-ci doit fréquemment accéder aux lignes des tables Singers et Albums pour une clé primaire donnée (par exemple, chaque fois que vous accédez à la ligne Singers(1), vous devez également accéder aux lignes Albums(1, 1) et Albums(1, 2)). En d'autres termes, Singers et Albums doivent avoir une relation forte de localité des données.

Vous pouvez déclarer cette relation de localité des données en créant la table Albums en tant que table enfant ou "entrelacée" de la table Singers. Comme indiqué dans la section Clés primaires, une table entrelacée est une table que vous déclarez en tant qu'enfant d'une autre table, car vous souhaitez que les lignes de la table enfant soient physiquement stockées avec les lignes de la table parente associée. Comme mentionné ci-dessus, le préfixe de la clé primaire d'une table enfant doit être la clé primaire de la table parent.

La ligne en gras du schéma ci-dessous montre comment créer la table Albums en tant que table entrelacée de Singers.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
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;

Remarques sur ce schéma :

  • SingerId, qui est le préfixe de la clé primaire de la table enfant Albums, est également la clé primaire de sa table parent Singers. Cette manière de procéder n'est pas obligatoire si les tables Singers et Albums se trouvent au même niveau de la hiérarchie, mais elle l'est dans ce schéma, car la table Albums est déclarée en tant qu'enfant de la table Singers.
  • L'annotation ON DELETE CASCADE signifie que, lorsqu'une ligne de la table parente est supprimée, ses lignes enfants dans cette table sont également automatiquement supprimées (c'est-à-dire toutes les lignes qui commencent par la même clé primaire). Si une table enfant ne comporte pas cette annotation ou si l'annotation affiche ON DELETE NO ACTION, vous devez supprimer les lignes enfants avant de pouvoir supprimer la ligne parent.
  • Les lignes entrelacées sont classées d'abord par lignes de la table parent, puis par lignes contiguës de la table enfant partageant la clé primaire du parent : "Singers(1)", puis "Albums(1, 1)", puis "Albums (1, 2) ", et ainsi de suite.
  • La relation de localité des données de chaque artiste et les données de leur album sont préservées si cette base de données est divisée, tant que la taille de la ligne d'un artiste et toutes les lignes Albums sont inférieures à 4 Go. aucun point d'accès sur ces lignes Albums.
  • La ligne parent doit exister pour que vous puissiez insérer des lignes enfants. La ligne parent peut soit déjà exister dans la base de données, soit être ajoutée avant l'insertion des lignes enfants dans la même transaction.

Disposition physique des lignes : les lignes de la table "Albums" sont entrelacées avec les lignes de la table "Singers" (Chanteurs)

Disposition physique des lignes de la table "Singers" et de sa table enfant "Albums".

Créer une hiérarchie de tables entrelacées

La relation parent-enfant entre les tables Singers et Albums peut être étendue à davantage de tables descendantes. Par exemple, vous pouvez créer une table entrelacée appelée Songs en tant qu'enfant de la table Albums pour stocker la liste des pistes de chaque album.

Table "Songs" (Chansons) comportant 6 lignes et 4 colonnes

Vue logique des lignes de la table "Songs". Les colonnes de clé primaire apparaissent à gauche de la ligne en gras.

La table Songs doit disposer d'une clé primaire composée de toutes les clés primaires des tables situées plus haut dans la hiérarchie, c'est-à-dire SingerId et AlbumId.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
--     + Songs (interleaved table, child table of Albums)
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;

Le schéma suivant illustre une vue physique des lignes entrelacées. Dans cet exemple, à mesure que le nombre de chanteurs augmente, Cloud Spanner ajoute des limites de division entre les chanteurs afin de préserver la localité des données entre un artiste et ses données de titre et d'album. Toutefois, si la taille d'une ligne d'artiste et de ses lignes enfants dépasse la limite de 4 Go, ou si un point d'accès est détecté dans les lignes enfants, Cloud Spanner tente d'ajouter des limites de division à _entrelacées.tables pour isoler cette ligne de point d'accès ainsi que toutes les lignes enfants situées en dessous.

Voici une vue physique des lignes entrelacées. À moins que la taille d'une seule ligne d'artiste et de toutes ses lignes enfants dépasse la limite de 4 Go, ou qu'un hotspot soit détecté dans les lignes enfants, Cloud Spanner privilégie l'ajout de limites de division entre chanteurs afin de préserver les données. la localisation entre un chanteur et ses données d'album et de chanson.

Vue physique des lignes : les lignes de la table "Songs" (Chansons) sont entrelacées avec les lignes de la table "Albums", qui sont entrelacées avec les lignes de la table "Singers" (Chanteurs).

Disposition physique des lignes des tables "Singers", "Albums" et "Songs", qui forment une hiérarchie de tables entrelacées.

En résumé, une table parent, et toutes ses tables enfants et descendantes, forment une hiérarchie de tables dans le schéma. Bien que chaque table de la hiérarchie soit logiquement indépendante, le fait de les entrelacer physiquement de cette manière peut améliorer les performances. En effet, l'entrelacement signifie que les tables sont pré-jointes, ce qui permet donc d'accéder aux lignes associées tout en minimisant les accès au disque.

Si possible, joignez des données dans des tables entrelacées par clé primaire. Étant donné que chaque ligne entrelacée est généralement stockée physiquement dans la même division que sa ligne parente, Cloud Spanner peut effectuer des jointures par clé primaire localement, ce qui minimise les accès au disque et le trafic réseau. Dans l'exemple suivant, les tables Singers et Albums sont jointes sur la clé primaire, SingerId:

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

L'entrelacement des tables dans Cloud Spanner est recommandé pour les données connexes de type un à plusieurs, fréquemment accessibles ensemble.

Colonnes de clé

Les clés d'une table ne peuvent pas changer ; vous ne pouvez ni ajouter, ni supprimer une colonne de clé dans une table existante.

Stocker des valeurs NULL

Vous pouvez définir des colonnes de clé primaire pour stocker des valeurs NULL. Si vous souhaitez stocker des valeurs NULL dans une colonne de clé primaire, omettez la clause NOT NULL pour cette colonne dans le schéma.

Voici un exemple d'omission de la clause NOT NULL dans la colonne de clé primaire SingerId. Notez que, puisque SingerId est la clé primaire, la table Singers ne peut contenir au maximum qu'une ligne qui stocke des valeurs NULL dans cette colonne.

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

La propriété pouvant accepter la valeur Null de la colonne de clé primaire doit correspondre aux déclarations des tables parents et enfants. Dans cet exemple, Albums.SingerId INT64 NOT NULL n'est pas autorisé. La déclaration de clé doit omettre la clause NOT NULL, car Singers.SingerId l'omet.

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

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

Types non autorisés

Les éléments ci-dessous ne peuvent pas être de type ARRAY :

  • Les colonnes de clé d'une table
  • Les colonnes de clé d'un index

Concevoir une architecture mutualisée

Si vous stockez des données appartenant à différents clients, il peut s'avérer bénéfique de travailler avec l'architecture mutualisée. Par exemple, un service de musique peut vouloir stocker les données de chaque maison de disque individuellement.

Architecture mutualisée classique

La méthode classique de conception d'une architecture mutualisée consiste à créer une base de données distincte pour chaque client. Dans cet exemple, chaque base de données possède sa propre table Singers :

Base de données 1 : Ackworth Records
SingerId FirstName LastName
1MarcRichards
2CatalinaSmith
Base de données 2 : Cama Records
SingerId FirstName LastName
3MarcRichards
4GabrielWright
Base de données 3 : Eagan Records
SingerId FirstName LastName
1BenjaminMartinez
2HannahHarris

Utiliser un modèle de gestion de données de schéma pour l'architecture mutualisée de Cloud Spanner

Une autre façon de concevoir une architecture mutualisée dans Cloud Spanner consiste à utiliser une valeur de clé primaire différente pour chaque client. Il s'agit d'inclure une colonne de clé CustomerId ou de clé similaire dans vos tables. Si vous faites de CustomerId la première colonne de clé, les données de chaque client ont une bonne localité. Cloud Spanner divise automatiquement vos données entre vos nœuds en fonction de la taille et des modèles de charge. Dans cet exemple, il existe une seule table Singers pour tous les clients :

Base de données Cloud Spanner à architecture mutualisée
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
23MarcRichards
24GabrielWright
31BenjaminMartinez
32HannahHarris

Si vous devez disposer de bases de données distinctes pour chaque locataire, vous devez prendre en compte les contraintes suivantes :

  • Le nombre autorisé de bases de données par instance et de tables par base de données est limité. En fonction du nombre de clients, il peut être impossible d'avoir des bases de données ou des tables séparées.
  • L'ajout de nouvelles tables et d'index non entrelacés peut prendre beaucoup de temps. Vous ne pourrez peut-être pas obtenir les performances souhaitées si la conception de votre schéma dépend de l'ajout de nouvelles tables et de nouveaux index.

Si vous souhaitez créer des bases de données séparées, il sera peut-être plus efficace de répartir vos tables sur plusieurs bases de données de sorte que chaque base de données subisse peu de modifications de schéma par semaine.

Si vous créez des tables et des index distincts pour chaque client de votre application, ne placez pas toutes les tables et tous les index dans la même base de données. Répartissez-les plutôt sur de nombreuses bases de données afin de minimiser les problèmes de performances liés à la création d'un grand nombre d'index. Le nombre autorisé de tables et d'index par base de données est lui aussi limité.

Pour en savoir plus sur les autres modèles de gestion des données et sur la conception d'applications pour l'architecture mutualisée, consultez la page Mettre en œuvre l'architecture mutualisée dans Cloud Spanner.