Dans Postgres-XL, les séquences sont conservées au niveau du Global Transaction Manager (GTM) pour s'assurer qu'elles reçoivent des valeurs non conflictuelles lorsqu'elles sont incrémentées à partir de plusieurs nœuds. Cela ajoute une surcharge importante pour une requête effectuant des milliers d'INSERTS dans une table avec une colonne en série, incrémentant la séquence une à la fois et effectuant un aller-retour réseau vers le GTM, pour chaque INSERT.
Dans un blog récent, Shaun Thomas s'est plaint du fait que les INSERTs s'exécutaient beaucoup plus lentement sur Postgres-XL que sur PostgreSQL vanille. Il existe déjà un moyen d'améliorer les performances des séquences, mais ce n'est clairement pas bien annoncé. J'ai pensé que c'était une bonne occasion d'expliquer l'installation.
Postgres-XL fournit un GUC configurable par l'utilisateur appelé sequence_range . Chaque backend demande un bloc de valeurs de séquence tel que contrôlé par ce GUC. Étant donné que COPY est couramment utilisé pour charger des données en bloc dans Postgres, Postgres-XL remplace automatiquement ce GUC pendant l'opération COPY et le définit sur 1000, améliorant ainsi considérablement les performances de COPY. Malheureusement, pour les INSERTs réguliers, la valeur par défaut est 1 et à moins que l'utilisateur ne définisse explicitement sequence_range à une valeur raisonnablement plus élevée, les performances d'INSERT en souffrent. Voici un exemple, utilisant le même exemple de schéma que celui utilisé par Shaun dans son article de blog.
CREATE TABLE sensor_log ( sensor_log_id SERIAL PRIMARY KEY, location VARCHAR NOT NULL, reading BIGINT NOT NULL, reading_date TIMESTAMP NOT NULL ) DISTRIBUTE BY HASH (sensor_log_id); postgres=# \timing Timing is on. postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 12067.911 ms postgres=# set sequence_range TO 1000; SET Time: 1.231 ms postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 397.406 ms
Donc, en définissant de manière appropriée sequence_range à 1 000, les performances de la requête INSERT ont été multipliées par près de 30.
Lorsque cette fonctionnalité a été ajoutée, la valeur par défaut de sequence_range GUC a été définie sur 1 car elle peut laisser des trous dans les valeurs de séquence. Mais en examinant les implications en termes de performances pour un cas d'utilisation très courant, nous avons décidé d'augmenter la valeur par défaut à 1000 et cela a maintenant été validé dans la branche XL9_5_STABLE du référentiel.
Il est important de noter que même si une valeur élevée de sequence_range améliorera les performances des séquences et des séries, il peut également laisser de grands trous dans les plages de séquences puisque les plages de séquences sont mises en cache au niveau du backend. Pour résoudre ce problème, Postgres-XL commence avec la valeur de paramètre CACHE spécifiée utilisée au moment de la création de la séquence et la double à chaque fois (limitée par sequence_range) si les séquences sont consommées à un taux très élevé.
Une amélioration similaire peut également être obtenue en augmentant la valeur du paramètre CACHE de la séquence afin qu'un bloc de valeurs de séquence soit mis en cache au niveau du backend. L'exemple suivant montre comment procéder pour une colonne série. Mais la sequence_range GUC fournit un moyen simple de remplacer la valeur par défaut globale et garantit également que les séquences ne sont mises en cache que lorsqu'elles sont incrémentées très rapidement.
postgres=# ALTER SEQUENCE sensor_log_sensor_log_id_seq CACHE 1000; ALTER SEQUENCE Time: 8.683 ms postgres=# SET sequence_range TO 1; SET Time: 2.341 ms postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 418.068 ms
Vous pouvez choisir l'une de ces techniques pour améliorer les performances. Bien que maintenant que la valeur par défaut de sequence_range est changé à 1000, peu d'utilisateurs peuvent voir la différence de performances.