【PostgreSQL 11 新機能】HASH パーティショニングを検証してみた

こんにちは。サイオステクノロジー OSS サポート担当 Y です。

今回は PostgreSQL 11 (現時点ではまだ beta 版) の新機能である “HASH パーティショニング” を検証してみました。(※以下の内容は CentOS 7.5/PostgreSQL 11beta3 にて検証しています。)

■はじめに

昨年リリースされた PostgreSQL 10 の新機能である Declarative Partitioning では、RANGE パーティションと LIST パーティションの 2つの種類のパーティションを作成することができるのですが、PostgreSQL 11 ではこれらに加えて “HASH パーティション” が実装される予定となっています。

今回は PostgreSQL 11beta3 を使って、この HASH パーティションを試してみようと思います。

■検証

さて、まずはテーブルを作成してみます。親テーブル “hash_test” に対して子テーブル “hash_child_1”, “hash_child_2”, “hash_child_3” を作成しています。

postgres=# CREATE TABLE hash_test (data text) PARTITION BY HASH (data);
CREATE TABLE
postgres=# 
postgres=# CREATE TABLE hash_child_1 PARTITION OF hash_test FOR VALUES WITH (MODULUS 3, REMAINDER 0);
CREATE TABLE
postgres=# 
postgres=# CREATE TABLE hash_child_2 PARTITION OF hash_test FOR VALUES WITH (MODULUS 3, REMAINDER 1);
CREATE TABLE
postgres=# 
postgres=# CREATE TABLE hash_child_3 PARTITION OF hash_test FOR VALUES WITH (MODULUS 3, REMAINDER 2);
CREATE TABLE
postgres=# 
postgres=# \d+ hash_test
                                Table "public.hash_test"
 Column | Type | Collation | Nullable | Default | Storage  | Stats target | Description 
--------+------+-----------+----------+---------+----------+--------------+-------------
 data   | text |           |          |         | extended |              | 
Partition key: HASH (data)
Partitions: hash_child_1 FOR VALUES WITH (modulus 3, remainder 0),
            hash_child_2 FOR VALUES WITH (modulus 3, remainder 1),
            hash_child_3 FOR VALUES WITH (modulus 3, remainder 2)

上記の通り、HASH パーティションの場合も RANGE/LIST パーティションと同様に CREATE TABLE 文だけでパーティショニングされたテーブルを作成することが可能です。

FOR VALUES 句に指定している値の詳細については、まだ正確に把握できていないのですが、以下のドキュメントによると “modulus は正の整数”, “remainder は modulus より小さい負ではない整数” 等の複数の条件があるようです。

それでは、作成したテーブルにデータを INSERT してみます。今回は以下の様なランダムな文字列を生成して INSERT してみました。

postgres=# INSERT INTO hash_test SELECT md5(clock_timestamp()::text) as test_data FROM generate_series(1,6);
INSERT 0 6
postgres=# 
postgres=# SELECT * FROM hash_test;
               data               
----------------------------------
 7b889830662255538e88baff30130545
 336d0b62f2020f380a4f08aa56c37b97
 40d27ceb4af48dc8cb6324ac287cf71f
 813de88f6844a517a7f617c75ac8583f
 b5d30b6de905a42faf636b68c30d13ce
 5bf0458863cf2f10566634b7addbbf7d
(6 rows)

親テーブルにデータが INSERT されたことが確認できたので、次に各子テーブルのデータを確認してみます。

postgres=# SELECT * FROM hash_child_1;
               data               
----------------------------------
 7b889830662255538e88baff30130545
 336d0b62f2020f380a4f08aa56c37b97
 40d27ceb4af48dc8cb6324ac287cf71f
(3 rows)

postgres=# 
postgres=# SELECT * FROM hash_child_2;
               data               
----------------------------------
 813de88f6844a517a7f617c75ac8583f
(1 row)

postgres=# 
postgres=# SELECT * FROM hash_child_3;
               data               
----------------------------------
 b5d30b6de905a42faf636b68c30d13ce
 5bf0458863cf2f10566634b7addbbf7d
(2 rows)

上記の通り、先ほど親テーブルに INSERT したデータが子テーブルに分散されていることが確認できました。

また、一般的な HASH パーティショニングのメリットとして “データを均等に分散することができる” というものがあります。

上記の例では、レコード数が少ないため均等に分散されているようには見えませんが、レコード数が増えればある程度均等に分散されるはずです。

ということで、実際に 300万レコードほどデータを INSERT して、データが均等に分散されるかを確認してみます。

postgres=# INSERT INTO hash_test SELECT md5(clock_timestamp()::text) as test_data FROM generate_series(1,3000000);
INSERT 0 3000000
postgres=# 
postgres=# SELECT count(*) FROM hash_test;
  count  
---------
 3000000
(1 row)

postgres=# 
postgres=# SELECT count(*) FROM hash_child_1;
  count  
---------
 1000535
(1 row)

postgres=# 
postgres=# SELECT count(*) FROM hash_child_2;
  count  
---------
 1000318
(1 row)

postgres=# 
postgres=# SELECT count(*) FROM hash_child_3;
 count  
--------
 999147
(1 row)

すると、各子テーブルにほぼほぼ均等に (約 100万レコードずつ) データが分散されていることが確認できました。

■最後に

今回は PostgreSQL 11 で実装予定の “HASH パーティショニング” を試してみました。

検証内容に記載してある通り、HASH パーティショニングはデータを均等に分散してくれるので、複数の異なるディスク上に作成したテーブルスペースと組み合わせると、I/O 負荷を均等に分散することができるので、大規模なテーブルに HASH パーティショニングを適用すると、当該テーブルにアクセスする際の性能向上等が期待できるかもしれません。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です