W Postgres-XL sekwencje są utrzymywane w Global Transaction Manager (GTM), aby zapewnić, że przypisywane są im wartości nie powodujące konfliktu, gdy są one zwiększane z wielu węzłów. Zwiększa to znaczne obciążenie dla zapytania wykonującego tysiące INSERT w tabeli z kolumną szeregową, zwiększając sekwencję pojedynczo i wykonując objazdową sieć do GTM, dla każdej INSERT.
Shaun Thomas w niedawnym blogu narzekał, że INSERTy działają wolniej na Postgres-XL w porównaniu z waniliowym PostgreSQL. Istnieje już sposób na poprawę wydajności sekwencji, ale najwyraźniej nie jest on dobrze reklamowany. Pomyślałem, że to dobra okazja, aby wyjaśnić tę funkcję.
Postgres-XL udostępnia konfigurowalny przez użytkownika GUC o nazwie sequence_range . Każdy backend żąda bloku wartości sekwencji kontrolowanych przez ten GUC. Biorąc pod uwagę, że COPY jest powszechnie używane do zbiorczego ładowania danych w Postgresie, Postgres-XL automatycznie nadpisuje ten GUC podczas operacji COPY i ustawia go na 1000, co znacznie poprawia wydajność COPY. Niestety, w przypadku zwykłych WSTAWEK wartością domyślną jest 1 i chyba że użytkownik wyraźnie ustawi sequence_range do rozsądnie wyższej wartości, ucierpi wydajność INSERT. Oto przykład, używając tego samego przykładowego schematu, którego użył Shaun w swoim poście na blogu.
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
Więc odpowiednio ustawiając sequence_range do 1000, wydajność zapytania INSERT poprawiła się prawie 30-krotnie.
Gdy ta funkcja została dodana, domyślna wartość parametru GUC zakres_sekwencji została ustawiona na 1, ponieważ może to pozostawić luki w wartościach sekwencji. Ale patrząc na implikacje wydajnościowe w bardzo powszechnym przypadku użycia, zdecydowaliśmy się zwiększyć wartość domyślną do 1000, co zostało teraz zatwierdzone w gałęzi XL9_5_STABLE repozytorium.
Należy zauważyć, że chociaż wysoka wartość sequence_range poprawi wydajność sekwencji i seriali, może również pozostawić duże dziury w zakresach sekwencji, ponieważ zakresy sekwencji są buforowane na poziomie zaplecza. Aby rozwiązać ten problem, Postgres-XL rozpoczyna się od określonej wartości parametru CACHE używanej podczas tworzenia sekwencji i podwaja ją za każdym razem (ograniczone przez zakres_sekwencji), jeśli sekwencje są zużywane z bardzo dużą szybkością.
Podobną poprawę można również osiągnąć, zwiększając wartość parametru CACHE sekwencji, tak aby porcja wartości sekwencji była buforowana na poziomie zaplecza. Poniższy przykład pokazuje, jak to zrobić dla kolumny szeregowej. Ale sequence_range GUC zapewnia łatwy sposób na zastąpienie globalnych wartości domyślnych, a także zapewnia, że sekwencje są buforowane tylko wtedy, gdy są bardzo szybko zwiększane.
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
Możesz wybrać dowolną z tych technik, aby poprawić wydajność. Chociaż teraz domyślna wartość sequence_range zmieniono na 1000, niewielu użytkowników może zauważyć różnicę w wydajności.