web-dev-qa-db-fra.com

Postgres accélère la création d'index pour une grande table

J'ai une grande table Postgres avec plus de 2 milliards d'entrées (1,5 To) et principalement des colonnes var non non nulles. Pour accélérer les insertions, j'ai supprimé les index avant le téléchargement en masse. Cependant, il faut maintenant une éternité pour que les index b-tree soient créés. Pour l'une des séries que j'ai raccourcies, il avait fallu> 12 heures pour créer les index.

Exemple de table et d'index que j'essaie de créer:

        Column         |            Type             | Modifiers 
-----------------------+-----------------------------+-----------
 name                  | character varying           | not null
 id                    | character varying           | 
 lifecycle_id          | character varying           | 
 dt                    | character varying           | 
 address               | character varying           | 
 ...

Indexes: 
"name_idx" PRIMARY KEY, btree (name)

"id_idx" btree (rec_id)

"lifecycle_id_idx" btree (lifecycle_id)

Le tableau actuel comporte 18 colonnes. J'ai mis le maintenance_work_mem à 15 Go. Cela fonctionne sur Postgres 9.6.11 sur RDS. La classe d'instance est db.m4.4xlarge.

Puisqu'il y a trois index, il serait difficile de trier les données avant l'insertion. Serait-il plus rapide de simplement insérer les données sans supprimer les index? Avez-vous d'autres suggestions pour accélérer la création de l'index?

3
Amy

PostgreSQL a ajouté la possibilité de paralléliser une génération d'index unique dans la version 10, vous pouvez donc envisager une mise à niveau pour utiliser cette fonctionnalité.

Même la version que vous utilisez actuellement, vous pouvez créer plusieurs index sur la même table en même temps (en utilisant différentes connexions à la base de données pour les invoquer chacune), vous pouvez donc toujours obtenir un certain degré de parallélisation informelle. Vous ne pouvez le faire qu'avec des générations d'index régulières, qui verrouillent les modifications apportées à la table pendant la génération de l'index. La génération d'index "simultanément" permet à UPDATE/INSERT/DELETE de s'exécuter simultanément avec la génération d'index, mais ne permet pas que les générations d'index sur la même table soient simultanées.

D'après mon expérience, les CPU virtuels d'AWS sont pratiquement inutiles. Alors que db.m4.4xlarge signale 16 vCPU, il est inutile de paralléliser au-delà de 8. Si vous voulez utiliser le parallélisme (soit v10 à un seul index, soit simplement en créant plusieurs index en même temps), vous avez probablement besoin d'un plus petit valeur pour maintenance_work_mem supérieure à 15 Go.

Serait-il plus rapide de simplement insérer les données sans supprimer les index?

À un moment donné, certainement. Cela dépend du nombre d'enregistrements dans vos encarts en vrac, ainsi que d'un tas d'autres choses, et on ne peut y répondre simplement en y réfléchissant. C'est une question expérimentale.

3
jjanes

La meilleure méthode de réglage pour créer des index est une valeur très élevée pour maintenance_work_mem.

Si vous ajoutez simplement quelques millions de lignes à une table 1.5 TB, la suppression et la recréation des index seront probablement plus lentes. Vous devrez exécuter des tests pour déterminer le point où elle commence à être plus rapide.

3
Laurenz Albe

Avant de poster cette question, j'avais deux tests en cours mais je ne savais pas s'ils finiraient jamais. J'espérais avoir un aperçu de la façon de l'accélérer s'ils n'avaient jamais terminé. Heureusement, l'un des tests s'est terminé. J'ai également obtenu de bons résultats en essayant les suggestions publiées par jjanes.

En utilisant Postgres 9, j'ai effectué deux tests:

  • Insertion des 2 milliards d'entrées avec index
  • Création d'index pour une table contenant déjà les 2 milliards d'entrées insérées

Le premier test est en cours depuis une semaine et n'a inséré que 20% des 2 milliards d'entrées. L'insertion avec index n'est certainement pas la voie à suivre.

Le deuxième test a duré 45 heures. Sans savoir combien de temps la création d'index allait prendre, j'ai interrompu prématurément certains des tests précédents et je n'ai jamais pu les voir terminés. Cela prend beaucoup de temps mais pour l'instant, je suis heureux que cela ne dure pas éternellement.

En prenant des suggestions jjanes, j'ai mis à niveau vers Postgres 11, défini les travailleurs parallèles sur 8 et défini la mémoire de travail de maintenance sur 7 Go. J'ai suivi ce guide pour choisir les paramètres: https://www.cybertec-postgresql.com/en/postgresql-parallel-create-index-for-better-performance/ . Cela a accéléré la création de l'index et n'a pris que 35 heures. Raser 10 heures était une belle surprise. Merci!

3
Amy