こんにちは。サイオステクノロジー OSS サポート担当 Y です。
今回は PostgreSQL 12 (現時点ではまだ beta 版) でのパラレルクエリについて検証してみました。(※以下の内容は CentOS 7.6/PostgreSQL 11.4/PostgreSQL 12beta2 にて検証しています。)
■はじめに
次の PostgreSQL のメジャーバージョンである PostgreSQL 12 では、複数の機能追加/強化が予定されています。今回は PostgreSQL 12beta2 を使って、パラレルクエリの動作を検証してみました。
PostgreSQL 11 までは、トランザクション分離レベルが SERIALIZABLE の場合、パラレルクエリが実行されません。しかし、PostgreSQL 12 からは、トランザクション分離レベルが SERIALIZABLE でもパラレルクエリが実行可能 (実行される可能性がある) になっています。
■PostgreSQL 11 で検証
まずは、PostgreSQL 11 での動作を確認してみます。
以下の様に、”READ COMMITTED”, “REPEATABLE READ”, “SERIALIZABLE” の 3つのトランザクション分離レベルで同じクエリ (パラレルクエリが実行されるようなクエリ) を実行してみました。
postgres=# SELECT version();
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 11.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
(1 row)
postgres=#
postgres=# CREATE TABLE test (a int);
CREATE TABLE
postgres=#
postgres=# INSERT INTO test VALUES (generate_series(1,1000000));
INSERT 0 1000000
postgres=#
postgres=# ANALYZE test;
ANALYZE
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Gather (cost=1000.00..10633.43 rows=1 width=4) (actual time=69.957..73.121 rows=0 loops=1)
Output: a
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on public.test (cost=0.00..9633.33 rows=1 width=4) (actual time=44.715..44.715 rows=0 loops=3)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 333333
Worker 0: actual time=32.550..32.550 rows=0 loops=1
Worker 1: actual time=32.487..32.487 rows=0 loops=1
Planning Time: 57.925 ms
Execution Time: 73.182 ms
(12 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Gather (cost=1000.00..10633.43 rows=1 width=4) (actual time=47.298..49.679 rows=0 loops=1)
Output: a
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on public.test (cost=0.00..9633.33 rows=1 width=4) (actual time=42.216..42.217 rows=0 loops=3)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 333333
Worker 0: actual time=40.835..40.835 rows=0 loops=1
Worker 1: actual time=39.839..39.839 rows=0 loops=1
Planning Time: 0.080 ms
Execution Time: 49.707 ms
(12 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------
Seq Scan on public.test (cost=0.00..16925.00 rows=1 width=4) (actual time=113.716..113.716 rows=0 loops=1)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 1000000
Planning Time: 0.098 ms
Execution Time: 113.744 ms
(6 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
すると、トランザクション分離レベルが SERIALIZABLE の場合のみ、パラレルクエリが実行されず、Seq Scan が実行されていることが確認できます。
■PostgreSQL 12beta2 で検証
次に、PostgreSQL 12beta2 での動作を確認してみます。
PostgreSQL 11 での検証と同じ様に、”READ COMMITTED”, “REPEATABLE READ”, “SERIALIZABLE” の 3つのトランザクション分離レベルで同じクエリ (パラレルクエリが実行されるようなクエリ) を実行しました。
postgres=# SELECT version();
version
------------------------------------------------------------------------------------------------------------
PostgreSQL 12beta2 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
(1 row)
postgres=#
postgres=# CREATE TABLE test (a int);
CREATE TABLE
postgres=#
postgres=# INSERT INTO test VALUES (generate_series(1,1000000));
INSERT 0 1000000
postgres=#
postgres=# ANALYZE test;
ANALYZE
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Gather (cost=1000.00..10633.43 rows=1 width=4) (actual time=73.917..75.779 rows=0 loops=1)
Output: a
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on public.test (cost=0.00..9633.33 rows=1 width=4) (actual time=47.272..47.273 rows=0 loops=3)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 333333
Worker 0: actual time=34.367..34.367 rows=0 loops=1
Worker 1: actual time=34.348..34.348 rows=0 loops=1
Planning Time: 2.284 ms
Execution Time: 75.825 ms
(12 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Gather (cost=1000.00..10633.43 rows=1 width=4) (actual time=58.102..60.504 rows=0 loops=1)
Output: a
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on public.test (cost=0.00..9633.33 rows=1 width=4) (actual time=52.118..52.119 rows=0 loops=3)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 333333
Worker 0: actual time=49.202..49.202 rows=0 loops=1
Worker 1: actual time=49.569..49.569 rows=0 loops=1
Planning Time: 0.175 ms
Execution Time: 60.540 ms
(12 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
postgres=# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN
postgres=#
postgres=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM test WHERE a = 0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Gather (cost=1000.00..10633.43 rows=1 width=4) (actual time=52.919..55.315 rows=0 loops=1)
Output: a
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on public.test (cost=0.00..9633.33 rows=1 width=4) (actual time=48.365..48.365 rows=0 loops=3)
Output: a
Filter: (test.a = 0)
Rows Removed by Filter: 333333
Worker 0: actual time=46.477..46.478 rows=0 loops=1
Worker 1: actual time=46.448..46.448 rows=0 loops=1
Planning Time: 0.121 ms
Execution Time: 55.351 ms
(12 rows)
postgres=#
postgres=# COMMIT;
COMMIT
postgres=#
すると、PostgreSQL 12beta2 ではトランザクション分離レベルが SERIALIZABLE の場合であっても、パラレルクエリが実行されていることが確認できました。
■最後に
今回は PostgreSQL 12beta2 でパラレルクエリの検証を実施してみました。PostgreSQL 9.6 でパラレルクエリが実装されて以降、バージョンアップを重ねるごとに少しずつ機能が強化されているようです。
今回検証した PostgreSQL 12 での強化で、パラレルクエリによる性能向上の恩恵を受けることができる範囲が広がったのではないでしょうか。
PostgreSQL 12 では様々な機能が強化されているので、次回も PostgreSQL 12 の新機能の検証を実施してみようと思います。

