PostgreSQL 9.5 ハッシュ性能向上

10月にPostgreSQL 9.5 betaもリリースされるっぽいですね。
今日は9.5の小ネタ?であるハッシュ性能向上効果を見てみた。

試してみた

手元の環境(Let's note SX4/VMWare Player/CentOS 7)上で、以下の様な2種類のテーブルを用意して、

hash=# \d test_a
    Table "public.test_a"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | not null
 data1  | integer | 
 data2  | text    | 
Indexes:
    "test_a_pkey" PRIMARY KEY, btree (id)

hash=# \d test_b
    Table "public.test_b"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | not null
 data1  | integer | 
 data2  | integer | 
 data3  | text    | 
Indexes:
    "test_b_pkey" PRIMARY KEY, btree (id)

hash=# 

こんな感じでテキトーに100万件ほどデータを突っ込んでおく。

INSERT INTO test_a VALUES (generate_series(1,1000000), random() * 1000000, md5(clock_timestamp()::text));
INSERT INTO test_b VALUES (generate_series(1,1000000), random() * 1000000, random() * 2000000, md5(clock_timestamp()::text));

こういう環境をPostgreSQL 9.4.4/9.5alpha2上に構築しておく。
そして、各バージョン毎にHash Joinによる検索を実行して、そのEXPLAIN ANALYZE結果を比較してみた。

9.4.4のEXPLAIN ANALYZE結果
[nuko@localhost 9.5-hash]$ postgres --version
postgres (PostgreSQL) 9.4.4
[nuko@localhost 9.5-hash]$ psql hash -e -f explain.sql 
EXPLAIN ANALYZE 
SELECT test_a.id, test_a.data2 
    FROM test_a INNER JOIN test_b ON test_a.data1 = test_b.data1 
    WHERE test_b.id < 1000;
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=40636.43..49770.10 rows=2124 width=37) (actual time=519.315..636.401 rows=943 loops=1)
   Hash Cond: (test_b.data1 = test_a.data1)
   ->  Index Scan using test_b_pkey on test_b  (cost=0.42..45.43 rows=1086 width=4) (actual time=0.009..0.234 rows=999 loops=1)
         Index Cond: (id < 1000)
   ->  Hash  (cost=19346.00..19346.00 rows=1000000 width=41) (actual time=518.490..518.490 rows=1000000 loops=1)
         Buckets: 8192  Batches: 32  Memory Usage: 2351kB
         ->  Seq Scan on test_a  (cost=0.00..19346.00 rows=1000000 width=41) (actual time=0.084..165.928 rows=1000000 loops=1)
 Planning time: 0.678 ms
 Execution time: 636.510 ms
(9 rows)
9.5alpha2のEXPLAIN ANALYZE結果
[nuko@localhost 9.5-hash]$ postgres --version
postgres (PostgreSQL) 9.5alpha2
[nuko@localhost 9.5-hash]$ psql hash -e -f explain.sql 
EXPLAIN ANALYZE 
SELECT test_a.id, test_a.data2 
    FROM test_a INNER JOIN test_b ON test_a.data1 = test_b.data1 
    WHERE test_b.id < 1000;
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=40636.43..49625.06 rows=1962 width=37) (actual time=357.597..447.943 rows=943 loops=1)
   Hash Cond: (test_b.data1 = test_a.data1)
   ->  Index Scan using test_b_pkey on test_b  (cost=0.42..43.05 rows=1007 width=4) (actual time=0.008..0.237 rows=999 loops=1)
         Index Cond: (id < 1000)
   ->  Hash  (cost=19346.00..19346.00 rows=1000000 width=41) (actual time=356.412..356.412 rows=1000000 loops=1)
         Buckets: 65536  Batches: 32  Memory Usage: 2826kB
         ->  Seq Scan on test_a  (cost=0.00..19346.00 rows=1000000 width=41) (actual time=0.027..150.604 rows=1000000 loops=1)
 Planning time: 0.612 ms
 Execution time: 448.060 ms
(9 rows)

Hash性能の比較

で、上記のEXPLAIN ANALYZE結果から、Hashの部分とHash演算の元となるSeqScanのactual timeを見てみる。。
Hashのactual timeとSeq Scanのactual timeの差分、これがハッシュ処理そのものの時間だと考えられる。
で、そのハッシュ処理(100万件分のハッシュ処理)そのものの時間を9.4.4と9.5alpha2と比較するとこんな感じに。

絶対値でみるとそれほどの時間ではないものの、9.4,4と9.5alphaで比較してみると、比率的にはかなりハッシュ処理の時間が向上していると思われる。
こういう小さな性能向上の積み重ねが、PostgreSQL全体の性能向上に繋がっているんだよなーと改めて思う。