Cette page fournit des instructions pour réaliser efficacement le chargement groupé de grandes quantités de données dans Spanner.
Plusieurs options s'offrent à vous pour charger des données de manière groupée dans Spanner:
- Insérez des lignes à l'aide du langage de manipulation de données (LMD).
- Insérez des lignes à l'aide de mutations.
- Importez des données à l'aide du connecteur Dataflow.
- Importez une base de données à l'aide de fichiers Avro.
- Importer des données au format CSV
Bien que vous puissiez également insérer des lignes à l'aide de Google Cloud CLI, nous vous déconseillons d'utiliser gcloud CLI pour le chargement groupé.
Consignes relatives aux performances pour le chargement groupé
Pour obtenir des performances de chargement groupé optimales, maximisez l'utilisation du partitionnement afin de répartir l'écriture des données sur les tâches de nœud de calcul.
Spanner utilise la répartition basée sur la charge pour répartir uniformément la charge des données sur les ressources de calcul de l'instance. Après quelques minutes de charge élevée, Spanner introduit des limites de division entre les lignes. En règle générale, si votre charge de données est bien distribuée et que vous suivez les bonnes pratiques relatives à la conception de schémas et au chargement groupé, votre débit en écriture devrait doubler toutes les quelques minutes jusqu'à ce que les ressources de processeur de l'instance soient saturées.
Partitionner les données par clé primaire
Spanner partitionne automatiquement les tables en plages plus petites. La clé primaire d'une ligne détermine où elle est partitionnée.
Pour obtenir un débit en écriture optimal pour les chargements groupés, partitionnez vos données par clé primaire selon ce modèle :
- Chaque partition contient une plage de lignes consécutives, déterminée par les colonnes de clé.
- Chaque commit contient des données pour une seule partition.
Nous vous recommandons d'utiliser un nombre de partitions 10 fois supérieur au nombre de nœuds de votre instance Spanner. Pour affecter des lignes aux partitions, procédez comme suit :
- Triez vos données par clé primaire.
- Divisez les données en 10 * (nombre de nœuds) partitions distinctes de taille égale.
- Créez et affectez une tâche de nœud de calcul distincte à chaque partition. La création des tâches de nœud de calcul s'effectue dans votre application. Il ne s'agit pas d'une fonctionnalité Spanner.
En suivant ce schéma, vous devriez constater un débit en écriture groupé global atteignant jusqu'à 10 à 20 Mo par seconde par nœud pour les charges importantes.
À mesure que vous chargez des données, Spanner crée et met à jour des divisions pour équilibrer la charge sur les nœuds de votre instance. Pendant ce processus, des baisses temporaires du débit peuvent survenir.
Exemple
Vous avez une configuration régionale avec trois nœuds. Vous disposez d'une table non entrelacée contenant 90 000 lignes. Les clés primaires de la table vont de 1 à 90 000.
- Lignes : 90 000
- Nœuds : 3
- Partitions : 10 * 3 = 30
- Lignes par partition : 90 000 / 30 = 3 000.
La première partition comprend la plage de clés 1 à 3 000. La deuxième partition comprend la plage de clés 3 001 à 6 000. La 30e partition comprend la plage de clés 87 001 à 90 000. (Il est déconseillé d'utiliser des clés séquentielles dans une grande table. Cet exemple n'est présenté qu'à des fins de démonstration.)
Chaque tâche de nœud de calcul envoie les écritures pour une partition. Dans chaque partition, vous devez écrire les lignes de manière séquentielle par clé primaire. L'écriture aléatoire de lignes en fonction de la clé primaire devrait également fournir un débit raisonnablement élevé. Vous pouvez exécuter des tests pour déterminer l'approche offrant les meilleures performances pour votre ensemble de données.
Chargement groupé sans partitionnement
Écrire un ensemble contigu de lignes dans un commit peut être plus rapide que d'écrire des lignes aléatoires. Les lignes aléatoires incluent également probablement des données provenant de différentes partitions.
Lorsque davantage de partitions sont écrites dans un commit, une coordination plus importante entre les serveurs est requise, ce qui augmente la latence et les frais généraux du commit.
Plusieurs partitions sont probablement impliquées, car chaque ligne aléatoire peut appartenir à une partition différente. Dans le pire des cas, chaque écriture implique toutes les partitions de votre instance Spanner. Comme indiqué précédemment, le débit en écriture est réduit lorsque davantage de partitions sont impliquées.
Éviter la surcharge
Il est possible d'envoyer plus de requêtes d'écriture que Spanner ne peut en gérer. Spanner gère la surcharge en annulant des transactions (c'est ce qu'on appelle un refus de transaction). Pour les transactions en écriture seule, Spanner relance automatiquement la transaction. Dans ce cas, le refus de transaction se traduit par une latence élevée. Lors de charges importantes, ce phénomène peut durer jusqu'à une minute. Lors de charges extrêmement lourdes, il peut durer plusieurs minutes. Pour éviter les refus de transaction, il est conseillé de limiter les requêtes d'écriture afin de maintenir l'utilisation du processeur dans des limites raisonnables. Les utilisateurs peuvent également augmenter le nombre de nœuds afin que l'utilisation du processeur reste dans les limites.
Commit entre 1 et 5 Mo de mutations à la fois
Chaque écriture dans Spanner entraîne une surcharge, que le volume de données à écrire soit volumineux ou non. Pour optimiser le débit, optimisez la quantité de données stockées par écriture. Les écritures de grande taille réduisent le ratio de surcharge par écriture. Un bonne technique pour ce faire serait que chaque commit mute des centaines de lignes. Lors de l'écriture de lignes relativement grandes, une taille de commit comprise entre 1 et 5 Mo offre généralement des performances optimales. Lors de l'écriture de petites valeurs ou de valeurs indexées, il est généralement préférable d'écrire au plus quelques centaines de lignes dans un même commit. Indépendamment de la taille de commit et du nombre de lignes, sachez qu'il existe une limite de 80 000 mutations par commit. Pour déterminer les performances optimales, vous devez tester et mesurer le débit.
Les commits supérieurs à 5 Mo ou contenant plus de quelques centaines de lignes n'offrent pas d'avantages supplémentaires et risquent de dépasser les limites imposées par Spanner en termes de taille de commit et de nombre de mutations par commit.
Consignes relatives aux index secondaires
Si votre base de données contient des index secondaires, vous devez choisir d'ajouter les index au schéma de base de données avant ou après le chargement des données de la table.
L'ajout de l'index avant le chargement des données permet de terminer immédiatement la modification du schéma. Cependant, chaque écriture affectant l'index prend plus de temps, car il doit également mettre à jour l'index. Une fois le chargement des données terminé, la base de données est immédiatement utilisable avec tous les index en place. Pour créer une table et ses index en même temps, envoyez les instructions DDL pour la nouvelle table et les nouveaux index dans une seule requête à Spanner.
L'ajout de l'index après le chargement des données signifie que chaque écriture est efficace. Cependant, la modification du schéma de chaque remplissage de l'index peut prendre beaucoup de temps. La base de données n'est pas entièrement utilisable, et les requêtes ne peuvent pas utiliser les index tant que toutes les modifications du schéma ne sont pas terminées. La base de données peut toujours répondre aux écritures et aux requêtes, mais à un débit plus lent.
Nous vous recommandons d'ajouter les index essentiels à votre application métier avant de charger les données. Pour tous les index non critiques, ajoutez-les après la migration des données.
Tester et mesurer le débit
Il peut s'avérer difficile de prédire le débit. C'est pourquoi nous vous recommandons de tester votre stratégie de chargement groupé avant d'exécuter le chargement final. Pour obtenir un exemple détaillé d'utilisation du partitionnement et de surveillance des performances, consultez la page relative à l'optimisation du débit de chargement de données.
Bonnes pratiques relatives au chargement groupé périodique dans une base de données existante
Si vous mettez à jour une base de données existante contenant des données, mais ne disposant d'aucun index secondaire, les recommandations de ce document s'appliquent toujours.
Si vous disposez d'index secondaires, ces instructions peuvent quand même vous permettre de bénéficier de performances raisonnables. Celles-ci dépendent du nombre moyen de divisions impliquées dans vos transactions. Si le débit est trop faible, vous pouvez essayer les solutions suivantes :
- Incluez moins de mutations dans chaque commit pour tenter d'augmenter le débit.
- Si la taille de l'importation est supérieure à la taille totale actuelle de la table mise à jour, supprimez les index secondaires, puis rajoutez-les une fois l'opération terminée. Cette étape n'est généralement pas indispensable, mais elle peut améliorer le débit.