0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Postgresql】テーブルのHash Partitionを試してみた

Posted at

ひとりごと

DB初心者が自身の備忘を兼ねて、Postgresqlで学んだことをアウトプットしようと思います

今回の目的

日々の業務でお客様が使用しているDBをいじることが多いのですが、
特定のテーブルが年々肥大化しており、ちょっとしたselectの応答が遅くなっていて困っています。(え、こんなに待たなきゃいけないの?ってくらい)

何か手段はないのかな?と調べたところ、Partitionというテーブルを分割する機能があるようなので、そちらの効果を簡単に検証してみて、お客様の提案活動に繋げてみたいな。という思いです:sunny:

Partitionとはなんぞ

簡単にはPartitionについて、調べてみました。
(といっても、以下の記事がわかりやすいので、こちらでは紹介だけ)
パーティショニングの概要

1.partitionの種類

No 種類 特徴
1 range 202010~202011といった範囲(期間)ごとにテーブルを分割
2 list 東京都、埼玉県、神奈川県といった種類ごとにテーブルを分割
3 hash 指定した分割数でテーブルを均等になるように分割

2.hash partitionについてもう少し詳しく

「指定した分割数でテーブルを均等になるように分割 」って何?ですよね

例えば、こんな感じのテーブルがあったとします。

id 所属部署 社員名
1 経理 太郎
2 営業 次郎
3 総務 三郎
4 総務 三郎
5 総務 三郎

これをHash partitionで「3つのpartitonに分ける」とする場合、
以下のような考え方で3テーブルに分別されます。

  • 1は3で割ると1余るのでテーブルAに格納
  • 2は3で割ると2余るのでテーブルBに格納
  • 3は3で割ると0余るのでテーブルCに格納
  • 4は3で割ると1余るのでテーブルAに格納

対象idを分割テーブル数で割ったあまりを使って、partitionテーブルに分別していく感じ

実際にpartitionテーブルを作って、性能比較してみる

まずは2つのテーブルを用意

partitionを有効にする以外は全く同じカラム・レコードのテーブルを用意しました
#省略していますが、各1000レコード用意してます。

  • partition_player

    id 所属部署 社員名
    1 営業 太郎
    2 営業 次郎
    3 総務 三郎
    4 総務 三郎
    5 総務 三郎
    1000 総務 千郎

    パーティション作成のSQL

    CREATE TABLE 
        player_01 PARTITION OF partition_player
    FOR 
        VALUES WITH (modulus 3, remainder 0)
    
    CREATE TABLE 
        player_02 PARTITION OF partition_player
    FOR 
        VALUES WITH (modulus 3, remainder 0)
    
    CREATE TABLE 
        player_03 PARTITION OF partition_player
    FOR 
        VALUES WITH (modulus 3, remainder 0)
    
    

  • employee

    id 所属部署 社員名
    1 営業 太郎
    2 営業 次郎
    3 総務 三郎
    4 総務 三郎
    5 総務 三郎
    1000 総務 千郎

用意したテーブルに対して同じクエリを投げてみる

  • 実行したクエリ
     explain analyze
    
    select
    	*
    from
    	practice.players_partitions
    where
    	id < 100
    
    

  • partitionあり統計

    "Append (cost=0.00..20.68 rows=97 width=70) (actual time=0.060..0.350 rows=99 loops=1)" " -> Seq Scan on players_01 players_partitions_1 (cost=0.00..5.96 rows=29 width=70) (actual time=0.058..0.142 rows=30 loops=1)" " Filter: (id < 100)" " Rows Removed by Filter: 207" " -> Seq Scan on players_02 players_partitions_2 (cost=0.00..7.04 rows=31 width=70) (actual time=0.017..0.088 rows=32 loops=1)" " Filter: (id < 100)" " Rows Removed by Filter: 211" " -> Seq Scan on players_03 players_partitions_3 (cost=0.00..7.20 rows=37 width=71) (actual time=0.024..0.093 rows=37 loops=1)" " Filter: (id < 100)" " Rows Removed by Filter: 219" "Planning Time: 0.756 ms" "Execution Time: 0.427 ms"


  • partitionなし統計

    "Seq Scan on players (cost=0.00..19.20 rows=99 width=70) (actual time=0.070..0.325 rows=99 loops=1)" " Filter: (id < 100)" " Rows Removed by Filter: 637" "Planning Time: 0.128 ms" "Execution Time: 0.364 ms"


  • 疑問
    なぜか?全てのpartitionga読み込まれてる。なぜだ?
    ⇨Hash Partitionなので、id <100としても、先ほど説明したとおり、
    対象idを分割テーブル数で割ったあまりを使って、partitionテーブルに分別なので、partition1~3それぞれにid<100が存在している。

 このことから、Hashで有効な検索方法は以下だと改めて理解しました

  • 実行したクエリ(修正版)

    explain analyze
    
    select
    	*
    from
    	practice.players_partitions
    where
    	id = 100
    
    

  • partitionあり統計(修正版実行時)
    ちゃんと一つのPartitionだけが読み込まれましたね!

    "Seq Scan on players_03 players_partitions (cost=0.00..7.20 rows=1 width=71) (actual time=0.024..0.084 rows=1 loops=1)"
    " Filter: (id = 100)"
    " Rows Removed by Filter: 255"
    "Planning Time: 2.021 ms"
    "Execution Time: 0.111 ms"

おわりに

以上です!誰かの理解の役に少しでも立つと嬉しいです(間違いがあったら指摘ください

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?