In Postgres-XL werden Sequenzen im Global Transaction Manager (GTM) verwaltet, um sicherzustellen, dass ihnen widersprüchliche Werte zugewiesen werden, wenn sie von mehreren Knoten inkrementiert werden. Dies fügt einen erheblichen Overhead für eine Abfrage hinzu, die Tausende von INSERTs in einer Tabelle mit einer seriellen Spalte durchführt, die Sequenz einzeln erhöht und für jede INSERT einen Netzwerk-Roundtrip zum GTM durchführt.
Shaun Thomas hat sich kürzlich in einem Blog darüber beschwert, dass INSERTs auf Postgres-XL im Vergleich zu Vanilla PostgreSQL um eine Größenordnung langsamer laufen. Es gibt bereits eine Möglichkeit, die Leistung für Sequenzen zu verbessern, aber es wird eindeutig nicht gut beworben. Ich dachte, das ist eine gute Gelegenheit, die Einrichtung zu erklären.
Postgres-XL bietet eine vom Benutzer einstellbare GUC namens sequence_range . Jedes Backend fordert einen Block von Sequenzwerten an, die von diesem GUC gesteuert werden. Angesichts der Tatsache, dass COPY häufig zum Massenladen von Daten in Postgres verwendet wird, überschreibt Postgres-XL diese GUC während des COPY-Vorgangs automatisch und setzt sie auf 1000, wodurch die COPY-Leistung erheblich verbessert wird. Leider ist der Standardwert für reguläre INSERTs 1, es sei denn, der Benutzer legt ausdrücklich sequence_range fest auf einen angemessen höheren Wert, leidet die INSERT-Leistung. Hier ist ein Beispiel, das dasselbe Musterschema verwendet, das Shaun in seinem Blogbeitrag verwendet hat.
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
Also durch entsprechendes Setzen von sequence_range auf 1000, Leistung der INSERT-Abfrage um fast das 30-fache verbessert.
Als diese Funktion hinzugefügt wurde, wurde der Standardwert von sequence_range GUC auf 1 gesetzt, da dies Lücken in den Sequenzwerten hinterlassen kann. Aber angesichts der Leistungsauswirkungen für einen sehr häufigen Anwendungsfall haben wir uns entschieden, den Standardwert auf 1000 zu erhöhen, und dies wurde nun in den XL9_5_STABLE-Zweig des Repositorys übernommen.
Es ist wichtig zu beachten, dass ein hoher Wert von sequence_range verbessert die Leistung für Sequenzen und Zeitschriften, kann aber auch große Lücken in Sequenzbereichen hinterlassen, da die Sequenzbereiche auf Backend-Ebene zwischengespeichert werden. Um dieses Problem zu beheben, beginnt Postgres-XL mit dem angegebenen CACHE-Parameterwert, der zum Zeitpunkt der Sequenzerstellung verwendet wird, und verdoppelt ihn jedes Mal (begrenzt durch sequence_range), wenn Sequenzen mit einer sehr hohen Rate verbraucht werden.
Eine ähnliche Verbesserung kann auch erreicht werden, indem der CACHE-Parameterwert der Sequenz erhöht wird, sodass ein Teil der Sequenzwerte auf der Backend-Ebene zwischengespeichert wird. Das folgende Beispiel zeigt, wie das für eine serielle Spalte gemacht wird. Aber der sequence_range GUC bietet eine einfache Möglichkeit, den globalen Standard zu überschreiben, und stellt außerdem sicher, dass die Sequenzen nur zwischengespeichert werden, wenn sie sehr schnell inkrementiert werden.
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
Sie können eine dieser Techniken wählen, um die Leistung zu verbessern. Obwohl jetzt der Standardwert von sequence_range auf 1000 geändert wird, sehen möglicherweise nicht viele Benutzer den Leistungsunterschied.