Cette page aborde les exigences relatives au schéma Spanner, explique comment utiliser le schéma pour créer des relations hiérarchiques et présente les fonctionnalités du schéma. Il introduit également les tables entrelacées, qui peuvent améliorer les performances des requêtes lorsque vous interrogez des tables dans une relation parent-enfant.
Un schéma est un espace de noms qui contient des objets de base de données, tels que des tables, des vues, des index et des fonctions. Vous utilisez des schémas pour organiser les objets, appliquer des droits d'accès précis et éviter les conflits de noms. Vous devez définir un schéma pour chaque base de données dans Spanner.
Vous pouvez également segmenter davantage et stocker les lignes de votre table de base de données dans différentes régions géographiques. Pour en savoir plus, consultez la présentation du partitionnement géographique.
Données fortement typées
Les données dans Spanner sont fortement typées. Les types de données incluent les types scalaires et complexes, qui sont décrits dans Types de données dans GoogleSQL et Types de données PostgreSQL.
Choisissez une clé primaire.
Les bases de données Spanner peuvent contenir une ou plusieurs tables. Les tableaux sont structurés en lignes et en colonnes. Le schéma de table définit une ou plusieurs colonnes de table comme clé primaire de la table, ce qui identifie de manière unique chaque ligne. Les clés primaires sont toujours indexées pour une recherche rapide des lignes. Si vous souhaitez mettre à jour ou supprimer les lignes existantes d'une table, celle-ci doit disposer d'une clé primaire. Une table sans colonne de clé primaire ne peut contenir qu'une seule ligne. Seules les bases de données utilisant le dialecte GoogleSQL peuvent contenir des tables sans clé primaire.
Souvent, votre application possède déjà un champ qui peut parfaitement remplir la fonction de clé primaire. Par exemple, pour une table Customers, il peut exister un CustomerId fourni par l'application qui sert de clé primaire. Dans d'autres cas, vous devrez peut-être générer une clé primaire lors de l'insertion de la ligne. Il s'agit généralement d'une valeur entière unique sans signification commerciale (une clé primaire de substitution).
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 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 point d'accès. 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.
- Utilisez 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.
Relations de table parents-enfants
Il existe deux façons de définir des relations parents-enfants dans Spanner : l'entrelacement des tables et les clés étrangères.
L'entrelacement des tables de Spanner est un bon choix pour de nombreuses relations parent-enfant. Avec l'entrelacement, Spanner colocalise physiquement les lignes enfant avec les lignes parent dans le stockage. La colocalisation peut améliorer considérablement les performances. Par exemple, si vous avez une table Customers et une table Invoices, et que votre application récupère fréquemment toutes les factures d'un client, vous pouvez définir Invoices en tant que table enfant entrelacée de Customers. Vous déclarez ainsi une relation de localité des données entre deux tables indépendantes. Vous indiquez à Spanner de stocker une ou plusieurs lignes de Invoices avec une ligne de Customers. Cette relation parent-enfant est appliquée lorsqu'elle est entrelacée avec la clause INTERLEAVE IN PARENT. Les tables enfants INTERLEAVE IN partagent les mêmes caractéristiques d'entrelacement physique des lignes, mais Spanner n'applique pas l'intégrité référentielle entre le parent et l'enfant.
Vous associez une table enfant à une table parente à l'aide d'un DDL qui déclare la table enfant comme entrelacée dans la table parente et en incluant la clé primaire de la table parente comme première partie de la clé primaire composite de la table enfant.
Pour en savoir plus sur l'entrelacement, consultez Créer des tables entrelacées.
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.
Google vous recommande de représenter les relations parents-enfants soit comme des tables entrelacées, soit comme des clés étrangères, mais pas les deux. 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 dans les tables entrelacées
Pour l'entrelacement, chaque table doit avoir une clé primaire. Si vous déclarez qu'une table est un enfant entrelacé d'une autre table, elle doit avoir une clé primaire composite qui inclut tous les composants de la clé primaire du parent, dans le même ordre, et généralement une ou plusieurs colonnes de table enfant supplémentaires.
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. Pour un exemple de lignes entrelacées, consultez Créer des tables entrelacées plus loin sur cette page.
En résumé, Spanner peut colocaliser physiquement des lignes de tables associées. Les exemples de schéma montrent à quoi ressemble la disposition physique résultante.
Divisions de base de données
Vous pouvez définir des hiérarchies de relations parent-enfant entrelacées allant jusqu'à sept couches, ce qui signifie que vous pouvez colocaliser les lignes de sept tables indépendantes. Si la taille des données dans vos tables n'est pas importante, un seul serveur 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 ? Spanner est une base de données distribuée. Cela signifie qu'à mesure que votre base de données s'agrandit, 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". Spanner ajoute et supprime automatiquement les limites de division en fonction de la taille et 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 Spanner effectue la répartition basée sur la charge afin de minimiser la création de points d'accès de lecture. Supposons que votre base de données contienne une table dans laquelle 10 lignes sont lues plus fréquemment que toutes les autres. Spanner peut ajouter des limites de fractionnement entre chacune de ces 10 lignes afin qu'elles soient chacune gérées par un serveur différent. Ainsi, on évite que la lecture de toutes ces lignes ne consomme les ressources d'un seul serveur.
En règle générale, si vous suivez les bonnes pratiques de conception de schéma, Spanner peut atténuer les hotspots de sorte que le débit en lecture devrait s'améliorer toutes les quelques minutes jusqu'à ce que les ressources de votre instance soient saturées ou que vous rencontriez des cas où aucune nouvelle limite de fractionnement ne peut être ajoutée (parce que vous avez un fractionnement qui ne couvre qu'une seule ligne sans enfant imbriqué).
Schémas nommés
Les schémas nommés vous aident à organiser les données similaires. Cela vous permet de trouver rapidement des objets dans la console Google Cloud , d'appliquer des droits d'accès et d'éviter les conflits de noms.
Les schémas nommés, comme les autres objets de base de données, sont gérés à l'aide du langage DDL.
Les schémas nommés Spanner vous permettent d'utiliser des noms complets pour interroger des données. Les FQN vous permettent de combiner le nom du schéma et le nom de l'objet pour identifier les objets de base de données. Par exemple, vous pouvez créer un schéma appelé warehouse pour l'unité commerciale "Entrepôt". Les tables qui utilisent ce schéma peuvent inclure product, order et customer information. Vous pouvez également créer un schéma appelé fulfillment pour l'unité commerciale chargée de l'exécution.
Ce schéma peut également comporter des tables appelées product, order et customer
information. Dans le premier exemple, le FQN est warehouse.product et dans le second, il est fulfillment.product. Cela évite toute confusion dans les situations où plusieurs objets partagent le même nom.
Dans le DDL CREATE SCHEMA, les objets de table reçoivent à la fois un FQN (par exemple, sales.customers) et un nom court (par exemple, sales).
Les objets de base de données suivants sont compatibles avec les schémas nommés :
TABLECREATEINTERLEAVE IN [PARENT]FOREIGN KEYSYNONYM
VIEWINDEXFOREIGN KEYSEQUENCE
Pour en savoir plus sur l'utilisation des schémas nommés, consultez Gérer les schémas nommés.
Utiliser un contrôle précis des accès avec des schémas nommés
Les schémas nommés vous permettent d'accorder un accès au niveau du schéma à chaque objet du schéma. Cela s'applique aux objets de schéma qui existent au moment où vous accordez l'accès. Vous devez accorder l'accès aux objets ajoutés ultérieurement.
Le contrôle des accès ultraprécis limite l'accès à des groupes entiers d'objets de base de données, tels que les tables, les colonnes et les lignes de la table.
Pour en savoir plus, consultez Accorder des droits de contrôle des accès précis à des schémas nommés.
Exemples de schéma
Les exemples de schéma de cette section montrent comment créer des tables parent et enfant avec et sans entrelacement, et illustrent les dispositions physiques correspondantes des données.
Créer une table parente
Supposons que vous créiez une application musicale et que vous ayez besoin d'une table qui stocke des lignes de données concernant des artistes :
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.
Vous pouvez définir la table avec la DDL suivante :
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 );
Veuillez noter ce qui suit à propos de l'exemple de schéma :
Singersest 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 entrelacé d'une autre table).- Pour les bases de données utilisant le dialecte GoogleSQL, les colonnes de clé primaire portent généralement l'annotation
NOT NULL(bien que vous puissiez l'omettre si vous souhaitez autoriser les valeursNULLdans les colonnes de clé). Pour en savoir plus, consultez Colonnes clés. - 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
STRINGouBYTESdans GoogleSQL doivent avoir une longueur définie, qui représente le nombre maximal de caractères Unicode pouvant être stockés dans le champ. La spécification de la longueur est facultative pour les types PostgreSQLvarcharetcharacter varying. Pour en savoir plus, consultez Types de données scalaires pour les bases de données utilisant le dialecte GoogleSQL et Types de données PostgreSQL pour les bases de données utilisant le dialecte PostgreSQL.
À quoi ressemble la disposition physique des lignes dans la table Singers ? Le diagramme suivant montre les lignes de la table Singers stockées par clé primaire ("Singers(1)", puis "Singers(2)", où le nombre entre parenthèses est la valeur de la clé primaire).
Le diagramme précédent 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. Lorsque cette table s'agrandit, il est possible que des lignes de données Singers soient stockées à des emplacements différents.
Créer des tables parent et enfant
Supposons que vous souhaitiez maintenant ajouter des données de base sur les albums de chaque artiste dans l'application musicale.
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)
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) );
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ë :
Remarque importante à propos du schéma : Spanner ne suppose aucune relation de localité des données entre les tables Singers et Albums, car il s'agit de tables de premier niveau. Au fur et à mesure que la base de données se développe, Spanner peut ajouter des limites de division entre toutes les lignes. 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, cela peut entraîner une perte de performances en raison de la nécessité de coordonner les lectures et les mises à jour sur différentes ressources. Si votre application doit fréquemment récupérer des informations sur tous les albums d'un artiste donné, vous devez créer la table Albums en tant que table enfant entrelacée de Singers, ce qui colocalise les lignes des deux tables en fonction de leur clé primaire. L'exemple suivant explique ce phénomène plus en détail.
Créer des tables entrelacées
Une table entrelacée est une table que vous déclarez comme enfant entrelacé 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é précédemment, la clé primaire de la table parente doit être la première partie de la clé primaire composite de la table enfant.
Une fois que vous avez entrelacé une table, l'opération est définitive. Vous ne pouvez pas annuler l'entrelacement. À la place, vous devez recréer le tableau et y migrer les données.
Lors de la conception de votre application musicale, supposons que vous vous rendiez compte que celle-ci doit fréquemment accéder aux lignes de la table Albums lorsqu'elle accède à une ligne Singers. Par exemple, lorsque vous accédez à la ligne Singers(1), vous devez également accéder aux lignes Albums(1, 1) et Albums(1, 2). Dans ce cas, les tables Singers et Albums doivent avoir une forte relation en termes de localité des données. Vous pouvez déclarer cette relation de localité des données en créant Albums en tant que table enfant entrelacée de Singers.
-- Schema hierarchy: -- + Singers -- + Albums (interleaved table, child table of Singers)
La ligne en gras du schéma ci-dessous montre comment créer la table Albums en tant que table entrelacée de 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;
Remarques sur ce schéma :
SingerId, qui est la première partie de la clé primaire de la table enfantAlbums, est également la clé primaire de sa table parentSingers.- L'annotation
ON DELETE CASCADEsignifie que lorsqu'une ligne de la table parente est supprimée, ses lignes enfants sont également automatiquement supprimées. Si une table enfant ne comporte pas cette annotation ou si l'annotation afficheON 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. Par exemple, "Singers(1)", puis "Albums(1, 1)", puis "Albums(1, 2)".
- La relation de localité des données de chaque chanteur avec les données de son album est préservée si cette base de données est divisée, à condition que la taille d'une ligne
Singerset de toutes ses lignesAlbumsreste inférieure à la limite de taille de division et qu'il n'y ait aucun hotspot dans aucune de ces lignesAlbums. - 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.
Supposons que vous souhaitiez modéliser Projects et leurs Resources sous forme de tables entrelacées. Certains scénarios pourraient bénéficier de INTERLEAVE IN, qui permet de ne pas exiger l'existence de la ligne Projects pour que les entités qui y sont associées existent (par exemple, un projet a été supprimé, mais ses ressources doivent être nettoyées avant d'être supprimées).
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;
Notez que dans cet exemple, nous utilisons la clause INTERLEAVE IN Projects plutôt que INTERLEAVE IN PARENT Projects. Cela indique que nous n'appliquons pas la relation parent-enfant entre les projets et les ressources.
Dans cet exemple, les lignes Resources(1, 10) et Resources(1, 20) peuvent exister dans la base de données même si la ligne Projects(1) n'existe pas. Projects(1) peut être supprimé même si Resources(1, 10) et Resources(1, 20) existent toujours. La suppression n'a aucune incidence sur ces lignes Resources.
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.
La table Songs doit disposer d'une clé primaire qui inclut 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)
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;
Le schéma suivant représente une vue physique des lignes entrelacées.
Dans cet exemple, au fur et à mesure que le nombre de chanteurs augmente, 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 d'album et de chanson. Toutefois, si la taille d'une ligne d'artiste et de ses lignes enfants dépasse la limite de taille de division, ou si un hotspot est détecté dans les lignes enfants, Spanner tente d'ajouter des limites de division afin d'isoler cette ligne du hotspot avec toutes les lignes enfants situées en dessous.
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 stockage.
Jointures avec des tables entrelacées
Si possible, joignez des données dans des tables entrelacées par clé primaire. Chaque ligne entrelacée étant généralement stockée physiquement dans la même division que sa ligne parente, Spanner peut localement effectuer des jointures par clé primaire, ce qui minimise les accès au stockage et le trafic réseau. Dans l'exemple suivant, Singers et Albums sont jointes sur la clé primaire 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;
Groupes de localités
Spanner utilise des groupes de localité pour préserver les relations de localité des données dans les colonnes des tables. Si vous ne créez pas explicitement de groupes de localité pour vos tables, Spanner regroupe toutes les colonnes dans le groupe de localité default et stocke les données de toutes les tables sur un stockage SSD. Vous pouvez utiliser les groupes de localités pour effectuer les opérations suivantes :
Utilisez le stockage hiérarchisé. Le stockage hiérarchisé est une fonctionnalité de stockage entièrement gérée qui vous permet de choisir de stocker vos données sur des disques durs SSD ou HDD. Par défaut, sans utiliser le stockage hiérarchisé, Spanner stocke toutes les données sur un stockage SSD.
Utilisez le regroupement de colonnes pour stocker les colonnes spécifiées séparément des autres colonnes. Comme les données des colonnes spécifiées sont stockées séparément, leur lecture est plus rapide que si toutes les données étaient regroupées. Pour utiliser le regroupement de colonnes, vous devez créer un groupe de localités sans spécifier d'options de stockage hiérarchisé. Spanner utilise des groupes de localité pour stocker les colonnes spécifiées séparément. Si elles sont spécifiées, les colonnes héritent de leur règle de stockage hiérarchisé à partir de la table ou du groupe de localités par défaut. Ensuite, utilisez l'instruction LDD
CREATE TABLEpour définir un groupe de localité pour les colonnes spécifiées ou l'instruction LDDALTER TABLEpour modifier le groupe de localité utilisé par la colonne d'une table. L'instruction LDD détermine les colonnes stockées dans le groupe de localités. Enfin, vous pouvez lire les données de ces colonnes plus efficacement.
Colonnes de clé
Cette section contient quelques notes sur les colonnes clés.
Modifier les clés de table
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 dans une clé primaire
Dans GoogleSQL, si vous souhaitez stocker NULL dans une colonne de clé primaire, omettez la clause NOT NULL pour cette colonne dans le schéma. (Les bases de données utilisant le dialecte PostgreSQL ne sont pas compatibles avec les valeurs NULL dans une colonne de clé primaire.)
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 ne peut contenir qu'une seule ligne qui stocke des valeurs NULL dans cette colonne.
CREATE TABLE Singers ( SingerId INT64 PRIMARY KEY, FirstName STRING(1024), LastName STRING(1024), );
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, NOT NULL pour la colonne Albums.SingerId n'est pas autorisé, car Singers.SingerId l'omet.
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;
Types non autorisés
Les colonnes suivantes ne peuvent pas être de type ARRAY :
- Les colonnes de clé d'une table
- Les colonnes de clé d'un index
Concevoir une base de données à architecture mutualisée
Si vous stockez des données appartenant à différents clients, vous souhaiterez peut-être pouvoir travailler avec l'architecture mutualisée. Par exemple, un service de musique peut vouloir stocker les contenus 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 :
| 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 |
Architecture mutualisée gérée par schéma
Une autre façon de concevoir une architecture mutualisée dans Spanner consiste à regrouper tous les clients dans une même table d'une même base de données et à utiliser une valeur de clé primaire différente pour chaque client. Par exemple, vous pouvez inclure une colonne de clé CustomerId dans vos tables. Si vous faites de CustomerId la première colonne de clé, les données de chaque client ont une bonne localité. Spanner peut ensuite utiliser efficacement les divisions de bases de données pour optimiser les performances en fonction de la taille des données et des modèles de charge. Dans l'exemple suivant, il existe une seule table Singers pour tous les clients :
| 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 |
Si vous devez disposer de bases de données distinctes pour chaque locataire, vous devez prendre en compte les contraintes suivantes :
- Le nombre de bases de données autorisées par instance, et le nombre de tables et d'index autorisés par base de données sont limités. 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.
Pour en savoir plus sur les autres modèles de gestion des données et la conception d'applications à architecture mutualisée, consultez Mettre en œuvre l'architecture mutualisée dans Spanner.