Ce document décrit les bonnes pratiques à suivre pour mettre à jour les schémas.
Procédures à suivre avant de commencer la mise à jour de schéma
Avant de lancer une mise à jour de schéma :
Assurez-vous que toutes les données existantes dans la base de données respectent les contraintes introduites par la mise à jour du schéma. Étant donné que certaines mises à jour de schéma dépendent des données réelles, et pas seulement du schéma actuel, une mise à jour réussie dans une base de données de test ne garantit pas la réussite dans une base de données de production. Voici quelques exemples courants :
- Si vous ajoutez une annotation
NOT NULLà une colonne existante, vérifiez qu'elle ne contient aucune valeurNULL. - Si vous réduisez la longueur autorisée d'une colonne
STRINGouBYTES, vérifiez que toutes les valeurs existantes de cette colonne respectent la contrainte de longueur.
- Si vous ajoutez une annotation
Si vous écrivez dans une colonne, une table ou un index qui doit subir une mise à jour de schéma, assurez-vous que les valeurs que vous ajoutez répondent aux nouvelles contraintes.
Si vous supprimez une colonne, une table ou un index, assurez-vous de ne pas continuer à l'utiliser en lecture ou en écriture.
Limitez la fréquence des mises à jour de schéma.
Si vous effectuez trop de mises à jour de schéma sur une courte période, Spanner peut limiter (throttle) le traitement des mises à jour de schéma en file d'attente. Ceci est dû au fait que Spanner limite la quantité d'espace disponible pour le stockage des versions de schéma. La mise à jour de votre schéma peut être limitée si la période de conservation comporte trop d'anciennes versions de schéma. Le taux maximal de modifications de schéma dépend de nombreux facteurs, dont le nombre total de colonnes dans la base de données. Par exemple, une base de données avec 2 000 colonnes (environ 2 000 lignes dans INFORMATION_SCHEMA.COLUMNS) peut effectuer au maximum 1 500 modifications de schéma (moins si la modification de schéma nécessite plusieurs versions) au cours de la période de conservation. Pour afficher l'état des mises à jour de schéma en cours, utilisez la commande gcloud spanner operations
list et filtrez les opérations de type DATABASE_UPDATE_DDL. Pour annuler une mise à jour de schéma en cours, utilisez la commande gcloud spanner operations
cancel et spécifiez l'ID d'opération.
La manière dont vos instructions LDD sont regroupées et leur ordre dans chaque lot peuvent affecter le nombre de versions de schéma qui en résultent. Pour optimiser le nombre de mises à jour de schéma que vous pouvez effectuer sur une période donnée, il est conseillé d'utiliser un traitement par lots qui réduit le nombre de versions de schéma. Quelques consignes sont décrites dans la section Mises à jour volumineuses.
Comme décrit dans la section Versions de schéma, certaines instructions LDD créent plusieurs versions de schéma. Celles-ci sont importantes pour le traitement par lot et l'ordre dans chaque lot. Deux principaux types d'instructions permettent de créer plusieurs versions de schéma :
- Les instructions pouvant nécessiter un remplissage des données d'index, telles que
CREATE INDEX. - Les instructions qui forcent Spanner à valider les données existantes, comme l'ajout de
NOT NULLou de contraintes de longueur.
Cependant, ces types d'instructions ne créent pas toujours plusieurs versions de schéma. Spanner essaiera de détecter quand ces types d'instructions peuvent être optimisés pour éviter d'utiliser plusieurs versions de schéma, ce qui dépend du traitement par lots. Par exemple, une instruction CREATE INDEX qui se trouve dans le même lot qu'une instruction CREATE TABLE pour la table de base de l'index, sans aucune instruction intermédiaire pour d'autres tables, peut éviter d'avoir à remplir les données de l'index, car Spanner peut garantir que la table de base est vide au moment de la création de l'index. La section Mises à jour volumineuses explique comment utiliser cette propriété pour créer efficacement de nombreux index.
Si vous ne pouvez pas grouper vos instructions LDD pour éviter de créer de nombreuses versions de schéma, vous devez limiter le nombre de mises à jour de schéma pour un même schéma de base de données pendant sa période de conservation. Augmentez la fenêtre temporelle dans laquelle vous effectuez les mises à jour de schéma pour permettre à Spanner de supprimer les anciennes versions du schéma avant d'en créer de nouvelles.
- Pour certains systèmes de gestion de bases de données relationnelles, il existe des packages logiciels qui effectuent toute une série de mises à jour de schéma (vers une version ultérieure ou antérieure) sur la base de données lors de chaque déploiement en production. Ces types de processus ne sont pas recommandés pour Spanner.
- Spanner est optimisé pour utiliser des clés primaires afin de partitionner les données pour des solutions d'architecture mutualisée. Si vous utilisez une solution d'architecture mutualisée qui utilise des tables distinctes pour chaque client, sachez que les mises à jour de schéma pour de nombreux clients à la fois peuvent générer beaucoup d'attente dans le traitement des opérations de mise à jour de schéma, occasionnant un temps de traitement important.
- Les mises à jour de schéma nécessitant une validation ou un remplissage d'index utilisent davantage de ressources de serveur, car chaque instruction crée plusieurs versions du schéma en interne.
Ordre d'exécution des instructions dans les lots
Si vous utilisez la Google Cloud CLI, l'API REST ou l'API RPC, vous pouvez émettre un lot d'une ou plusieurs instructions CREATE, ALTER ou DROP.
Spanner applique les instructions d'un même lot dans l'ordre, en s'arrêtant à la première erreur. Si l'application d'une instruction entraîne une erreur, cette instruction est annulée. Les instructions du lot précédemment appliquées ne sont en revanche pas annulées. Cette application d'instructions dans l'ordre signifie que si vous souhaitez que les instructions nécessitant un remplissage inévitable s'exécutent en parallèle (comme la création de plusieurs index sur de grandes tables existantes), vous devez les envoyer dans des lots distincts, car chaque remplissage peut prendre beaucoup de temps. Si vous créez une table avec des index, la bonne pratique consiste à les placer ensemble (CREATE TABLE suivi de CREATE INDEX) dans un même lot pour éviter complètement le remplissage.
Spanner peut combiner et réorganiser des instructions de différents lots dans une seule modification atomique appliquée à la base de données. Au sein de chaque modification atomique, les instructions des différents lots se déroulent dans un ordre arbitraire. Par exemple, si un lot d'instructions contient ALTER TABLE table_name ALTER COLUMN column_name STRING(50) et un autre contient ALTER TABLE table_name ALTER COLUMN
column_name STRING(20), Spanner conserve cette colonne dans l'un de ces deux états, mais sans spécifier lequel.
Options pour les mises à jour de schéma volumineuses
La meilleure façon de créer une table et un grand nombre d'index sur cette table est de les créer tous en même temps, de sorte qu'une seule version de schéma soit créée. Il est recommandé de créer les index immédiatement après la table dans la liste des instructions LDD. Vous pouvez créer la table et ses index lors de la création de la base de données ou via un seul grand groupe d'instructions. Si vous devez créer plusieurs tables, chacune avec de nombreux index, vous pouvez inclure toutes les instructions dans un seul lot. Vous pouvez inclure plusieurs milliers d'instructions dans un seul lot lorsque toutes les instructions peuvent être exécutées ensemble à l'aide d'une seule version de schéma.
Lorsqu'une instruction nécessite un remplissage des données d'index ou une validation de données, elle ne peut pas être exécutée dans une seule version de schéma. Cela se produit pour les instructions CREATE INDEX lorsque la table de base de l'index existe déjà (soit parce qu'elle a été créée dans un lot d'instructions LDD précédent, soit parce qu'une instruction du lot entre les instructions CREATE TABLE et CREATE INDEX nécessitait plusieurs versions de schéma. Spanner nécessite qu'il n'y ait pas plus de 10 instructions de ce type dans un seul lot. La création d'index nécessitant un remplissage, en particulier, utilise plusieurs versions de schéma par index. Il est donc recommandé de ne pas créer plus de trois nouveaux index nécessitant un remplissage par jour (quelle que soit la manière dont ils sont regroupés, à moins que ce regroupement ne permette d'éviter le remplissage).
Par exemple, ce lot d'instructions utilisera une seule version de schéma :
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
En revanche, ce lot utilisera de nombreuses versions de schéma, car UnrelatedIndex nécessite un remplissage (puisque sa table de base doit avoir déjà existé), ce qui oblige tous les index suivants à nécessiter également un remplissage (même s'ils font partie du même lot que leurs tables de base) :
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, 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); CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Il est préférable de déplacer la création de UnrelatedIndex à la fin du lot, ou vers un autre lot, afin de réduire les versions de schéma.
Attendre que les demandes d'API soient terminées
Lorsque vous effectuez des requêtes projects.instances.databases.updateDdl (API REST) ou UpdateDatabaseDdl (API RPC), utilisez projects.instances.databases.operations.get (API REST) ou GetOperation (API RPC), respectivement, pour attendre que chaque requête soit terminée avant d'en lancer une nouvelle. En attendant la fin de chaque requête, votre application peut suivre la progression de vos mises à jour de schéma. Cela permet également de conserver le volume des mises à jour de schéma en attente à une taille raisonnable.
Chargement groupé
Lorsque vous chargez des données de façon groupée dans une nouvelle table, vous pouvez créer des index secondaires avant ou après le chargement des données. Le chargement des données est plus rapide si vous créez des index après le chargement, mais cela signifie que les index doivent être remplis.
Si vous chargez d'abord les données, puis créez les index, l'ingestion de données est plus rapide, car seule la table est écrite. Les remplissages d'index ultérieurs peuvent écrire les données d'index dans des lots optimisés, ce qui est plus efficace que d'écrire les données d'index en même temps que les données de table. Toutefois, le remplissage des index nécessite plusieurs versions de schéma et est soumis à des limites. Comme indiqué dans les options pour les mises à jour volumineuses, vous ne devez pas créer plus de 10 index nécessitant un remplissage dans un même lot. Il est préférable de ne pas créer plus de trois index de ce type par jour.
Vous pouvez également créer des tables et des index dans le même lot, comme décrit dans Options pour les mises à jour volumineuses. Cela évite le remplissage des index, mais le chargement groupé des données sera plus lent, car chaque index doit être mis à jour à mesure que les données sont chargées.
Le meilleur choix dans une situation donnée dépend de la quantité de données à charger, des clés spécifiques de la table et de l'index, du nombre d'index nécessaires et de la fréquence à laquelle les opérations de chargement groupé seront requises dans la même base de données. En règle générale, il est préférable de créer les index séparément si une grande quantité de données doit être chargée dans chaque table et que seuls quelques index sont nécessaires.