Effectuer des mises à jour de schéma

Spanner vous permet d'effectuer des mises à jour de schéma sans temps d'arrêt. Vous pouvez mettre à jour le schéma d'une base de données existante de plusieurs manières :

Mises à jour de schéma compatibles

Spanner permet d'effectuer les mises à jour de schéma suivantes pour les bases de données existantes :

  • Ajoutez ou supprimez un schéma nommé.
  • créer une table ; Les colonnes des nouvelles tables peuvent avoir la valeur NOT NULL.
  • Supprimer une table si elle ne comporte pas de table entrelacée et si elle n'a pas d'index secondaire.
  • Créer ou supprimer une table avec une clé étrangère
  • Ajouter ou supprimer une clé étrangère dans une table existante.
  • Ajouter une colonne non-clé à n'importe quelle table. Les nouvelles colonnes non-clés ne peuvent pas avoir la valeur NOT NULL.
    • Supprimer une colonne non-clé de n'importe quelle table, sauf si elle est utilisée par un index secondaire, une clé étrangère, une colonne générée stockée ou une contrainte de vérification.
  • Ajouter NOT NULL à une colonne non-clé, à l'exception des colonnes ARRAY.
  • Supprimer la valeur NOT NULL d'une colonne non-clé.
  • Remplacer une colonne STRING par une colonne BYTES, ou une colonne BYTES par une colonne STRING.
  • Remplacer une colonne PROTO par une colonne BYTES, ou une colonne BYTES par une colonne PROTO.
  • Modifiez le type de message proto d'une colonne PROTO.
  • Ajoutez de nouvelles valeurs à une définition ENUM et renommez les valeurs existantes à l'aide de ALTER PROTO BUNDLE.
  • Modifiez les messages définis dans un PROTO BUNDLE de manière arbitraire, à condition que les champs modifiés de ces messages ne soient pas utilisés comme clés dans une table et que les données existantes respectent les nouvelles contraintes.
  • Augmenter ou diminuer la longueur maximale d'un type STRING ou BYTES (y compris la valeur MAX), sauf s'il s'agit d'une colonne de clé primaire héritée d'une ou de plusieurs tables enfants.
  • Augmenter ou diminuer la longueur maximale d'une colonne ARRAY<STRING>, ARRAY<BYTES> ou ARRAY<PROTO> jusqu'à la valeur autorisée.
  • Activer ou désactiver les horodatages de commit dans les colonnes de valeur et de clé primaire.
  • Ajouter ou supprimer un index secondaire.
  • Ajouter ou supprimer une contrainte de vérification dans une table existante.
  • Ajouter ou supprimer une colonne générée stockée dans une table existante.
  • Créez un package de statistiques de l'optimiseur.
  • créer et gérer des vues.
  • créer et gérer des séquences.
  • Créez des rôles de base de données et accordez des droits d'accès.
  • Définissez, modifiez ou supprimez la valeur par défaut d'une colonne.
  • Modifiez les options de la base de données (default_leader ou version_retention_period, par exemple).
  • créer et gérer des flux de modifications.
  • Créer et gérer des modèles de ML

Mises à jour de schéma non compatibles

Spanner ne permet pas d'effectuer les mises à jour de schéma suivantes pour les bases de données existantes :

  • S'il existe un champ PROTO de type ENUM référencé par une clé de table ou d'index, vous ne pouvez pas supprimer les valeurs ENUM des énumérations proto. (La suppression des valeurs ENUM des énumérations utilisées par les colonnes ENUM<> est acceptée, y compris lorsque ces colonnes sont utilisées comme clés.)

  • Remplacer une colonne STRING(36) par une colonne UUID, ou une colonne UUID par une colonne STRING(36).

Performances de la mise à jour de schéma

Les mises à jour de schéma dans Spanner ne nécessitent pas de temps d'arrêt. Lorsque vous soumettez un lot d'instructions LDD à une base de données Spanner, vous pouvez continuer à écrire et à lire dans la base de données sans interruption, pendant que Spanner applique la mise à jour en tant qu'opération de longue durée.

La durée d'exécution d'une instruction DDL varie en fonction de la nécessité de valider les données existantes ou de remplir des données. Par exemple, si vous ajoutez l'annotation NOT NULL à une colonne existante, Spanner doit lire toutes les valeurs de la colonne pour s'assurer qu'elle ne contient aucune valeur NULL. Cette étape peut être longue s'il y a beaucoup de données à valider. Prenons comme autre exemple l'ajout d'un index à une base de données : Spanner remplit l'index à l'aide des données existantes. Ce processus peut durer longtemps en fonction de la manière dont est défini l'index et de la taille de la table de base correspondante. Cependant, si vous ajoutez une colonne à une table, il n'y a pas de données existantes à valider. Par conséquent, Spanner peut effectuer la mise à jour plus rapidement.

En résumé, les mises à jour de schéma ne nécessitant pas que Spanner valide les données existantes peuvent s'effectuer en quelques minutes. Les mises à jour de schéma nécessitant une validation peuvent prendre plus longtemps, en fonction de la quantité de données existantes à valider. Cependant, la validation des données s'effectue en arrière-plan avec une priorité moindre que celle du trafic de production. Les mises à jour de schéma nécessitant une validation des données sont abordées plus en détail dans la section suivante.

Mises à jour de schéma validées par rapport aux définitions de vue

Lorsque vous effectuez une mise à jour de schéma, Spanner vérifie que la mise à jour n'invalide pas les requêtes utilisées pour définir les vues existantes. Si la validation réussit, la mise à jour du schéma réussit. Si la validation échoue, la mise à jour du schéma échoue. Pour en savoir plus, consultez Bonnes pratiques lors de la création de vues.

Mises à jour de schéma nécessitant une validation des données

Certaines mises à jour de schéma nécessitent de vérifier que les données existantes répondent aux nouvelles contraintes. Lorsqu'une mise à jour de schéma nécessite la validation des données, Spanner interdit les mises à jour de schéma en conflit avec les entités de schéma concernées et valide les données en arrière-plan. Si la validation réussit, la mise à jour du schéma réussit. Si la validation échoue, la mise à jour du schéma échoue également. Les opérations de validation sont exécutées comme des opérations de longue durée. Vous pouvez vérifier le statut de ces opérations pour savoir si elles ont réussi ou échoué.

Par exemple, supposons que vous ayez défini le fichier music.proto suivant avec un enum RecordLabel et un message de protocole Songwriter :

  enum RecordLabel {
    COOL_MUSIC_INC = 0;
    PACIFIC_ENTERTAINMENT = 1;
    XYZ_RECORDS = 2;
  }

  message Songwriter {
    required string nationality   = 1;
    optional int64  year_of_birth = 2;
  }

Pour ajouter une table Songwriters à votre schéma :

GoogleSQL

CREATE PROTO BUNDLE (
  googlesql.example.music.Songwriter,
  googlesql.example.music.RecordLabel,
);

CREATE TABLE Songwriters (
  Id         INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  Nickname   STRING(MAX),
  OpaqueData BYTES(MAX),
  SongWriter googlesql.example.music.Songwriter
) PRIMARY KEY (Id);

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

Les mises à jour de schéma suivantes sont autorisées, mais elles nécessitent une validation et peuvent durer longtemps selon la quantité de données existantes :

  • Ajouter la valeur NOT NULL à une colonne non-clé. Exemple :

    ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
    
  • Réduire la longueur d'une colonne. Exemple :

    ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
    
  • Remplacer le type BYTES par STRING. Exemple :

    ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
    
  • Remplacer le type INT64/INT32 par ENUM. Exemple :

    ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
    
  • Suppression des valeurs existantes de la définition de l'énumération RecordLabel.

  • Activer les horodatages de commit sur une colonne TIMESTAMP existante. Exemple :

    ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
    
  • Ajouter une contrainte de vérification à une table existante.

  • Ajouter une colonne générée stockée à une table existante.

  • Créer une nouvelle table avec une clé étrangère.

  • Ajouter une clé étrangère à une table existante.

Ces mises à jour de schéma échouent si les données sous-jacentes ne répondent pas aux nouvelles contraintes. Par exemple, l'instruction ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL échoue si la colonne Nickname contient NULL, car les données existantes ne respectent pas la contrainte NOT NULL de la nouvelle définition.

La validation des données peut prendre de quelques minutes à plusieurs heures. Le temps nécessaire à cette validation dépend des éléments suivants :

  • Taille de l'ensemble de données
  • La capacité de calcul de l'instance
  • La charge sur l'instance

Certaines mises à jour de schéma peuvent modifier le comportement des requêtes adressées à la base de données avant la fin de la mise à jour. Par exemple, si vous ajoutez NOT NULL à une colonne, Spanner commence presque immédiatement à rejeter les écritures pour les nouvelles requêtes qui utilisent NULL pour la colonne. Si finalement la mise à jour du nouveau schéma échoue lors de la validation des données, il y aura eu une période pendant laquelle les écritures auront été bloquées, même si l'ancien schéma les avait acceptées.

Vous pouvez annuler une opération de validation des données de longue durée à l'aide de la méthode projects.instances.databases.operations.cancel ou en utilisant gcloud spanner operations.

Versions de schéma créées lors des mises à jour de schéma

Spanner utilise la gestion des versions de schéma pour éviter tout temps d'arrêt pendant la mise à jour du schéma dans une base de données volumineuse. Spanner conserve l'ancienne version du schéma pour permettre les opérations de lecture pendant la mise à jour du schéma. Spanner crée ensuite une ou plusieurs versions du schéma pour procéder à la mise à jour de ce dernier. Chaque version contient le résultat d'une collection d'instructions dans une modification atomique unique.

Chaque version de schéma ne correspond pas nécessairement à un lot d'instructions DDL ou à une instruction DDL individuelle. Certaines instructions LDD individuelles, comme la création d'index pour les tables de base existantes ou les instructions nécessitant une validation des données, génèrent plusieurs versions de schéma. Dans d'autres cas, plusieurs instructions DDL peuvent être regroupées dans une même version. Les anciennes versions de schéma peuvent consommer d'importantes ressources en termes de serveur et de stockage, et sont conservées jusqu'à leur expiration (plus nécessaires pour diffuser des lectures d'anciennes versions des données).

Le tableau suivant indique le temps nécessaire à Spanner pour mettre à jour un schéma.

Opération sur le schéma Durée approximative
CREATE TABLE Minutes
CREATE INDEX

Quelques minutes, voire plusieurs heures, si la table de base est créée avant l'index.

Quelques minutes, si l'instruction est exécutée en même temps que l'instruction CREATE TABLE pour la table de base.

DROP TABLE Minutes
DROP INDEX Minutes
ALTER TABLE ... ADD COLUMN Minutes
ALTER TABLE ... ALTER COLUMN

Quelques minutes, voire plusieurs heures, si une validation en arrière-plan est nécessaire.

Quelques minutes, si la validation en arrière-plan n'est pas requise.

ALTER TABLE ... DROP COLUMN Minutes
ANALYZE

De quelques minutes à quelques heures, selon la taille de la base de données.

Modifications des types de données et flux de modifications

Si vous modifiez le type de données d'une colonne qu'un flux de modifications surveille, le champ column_types des enregistrements du flux de modifications ultérieurs concernés reflète son nouveau type, tout comme les données JSON old_values dans le champ mods des enregistrements.

Le new_values du champ mods d'un enregistrement de flux de modification correspond toujours au type actuel d'une colonne. La modification du type de données d'une colonne observée n'affecte pas les enregistrements de flux de modifications antérieurs à cette modification.

Dans le cas particulier d'un changement de BYTES en STRING, Spanner valide les anciennes valeurs de la colonne lors de la mise à jour du schéma. Par conséquent, Spanner a décodé en toute sécurité les anciennes valeurs de type BYTES en chaînes au moment où il écrit les enregistrements de flux de modifications ultérieurs.