13
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PostgreSQLでパーティション数が多いほどプラン生成時間が長くなる問題の確認

Posted at

PostgreSQLのパーティショニング機能には、パーティション数が多いほど親パーティションに対するクエリのプラン生成時間が長くなる問題がある。これは、PostgreSQL10のネイティブ・パーティショニング機能でも従来のパーティショニング機能でも同様である。

今回は以下5パターンにおけるクエリのプラン生成時間を比較して、パーティション数が多いほどプラン生成時間が長くなることを確認する。

  1. パーティション分割しない
  2. 10パーティションに分割
  3. 100パーティションに分割
  4. 500パーティションに分割
  5. 1000パーティションに分割

PostgreSQL10のネイティブ・パーティショニングの場合

-- 指定の数だけ分割されたパーティションを作成する関数を登録する
CREATE OR REPLACE FUNCTION create_partition_native (
  parent TEXT, num INT
) RETURNS VOID AS $$
DECLARE
  i INT;
  child TEXT;
BEGIN
  -- パーティション作成は、v10のネイティブ・パーティショニング機能の構文で行う
  EXECUTE 'CREATE TABLE ' || parent || ' (key INT, val TEXT)' ||
    ' PARTITION BY LIST (key)';
  FOR i IN 1 .. num LOOP
    child := parent || '_' || to_char(i, 'FM0000000');
    EXECUTE 'CREATE TABLE ' || child || ' PARTITION OF ' || parent ||
      ' (PRIMARY KEY(key)) FOR VALUES IN (' || i || ')';
  END LOOP;
END;
$$ LANGUAGE plpgsql;

-- 分割数が10、100、500、1000のパーティションを作成する
SELECT create_partition_native('native_0010', 10);
SELECT create_partition_native('native_0100', 100);
SELECT create_partition_native('native_0500', 500);
SELECT create_partition_native('native_1000', 1000);

-- 各分割数のパーティション上でクエリのEXPLAIN ANALYZEを実行し、プラン生成時間を確認する
EXPLAIN ANALYZE SELECT * FROM native_0010_0000009 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM native_0010 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM native_0100 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM native_0500 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM native_1000 WHERE key = 9;

各パターン、5回ずつEXPLAIN ANALYZEを実行したときのプラン生成時間の中間値は以下のとおり。

項番 パターン プラン生成時間(ms)
1 パーティション分割しない 0.045
2 10パーティションに分割 0.191
3 100パーティションに分割 1.397
4 500パーティションに分割 70.353
5 1000パーティションに分割 138.918

PostgreSQL10のネイティブ・パーティショニング機能でも、パーティション数が多いほどプラン生成時間が長くなることを確認できる。

従来のパーティショニング機能の場合

-- 指定の数だけ分割されたパーティションを作成する関数を登録する
CREATE OR REPLACE FUNCTION create_partition_traditional (
  parent TEXT, num INT
) RETURNS VOID AS $$
DECLARE
  i INT;
  child TEXT;
BEGIN
  -- パーティション作成は、従来のパーティショニング機能の構文で行う
  -- 本来はパーティションへのINSERT用にトリガを作成するが、今回の検証には不要なため作成しない
  EXECUTE 'CREATE TABLE ' || parent || ' (key INT PRIMARY KEY, val TEXT)';
  FOR i IN 1 .. num LOOP
    child := parent || '_' || to_char(i, 'FM0000000');
    EXECUTE 'CREATE TABLE ' || child || ' (LIKE ' || parent ||
      ' INCLUDING INDEXES, CHECK(key = ' || i || ')) INHERITS (' ||
      parent || ')';
  END LOOP;
END;
$$ LANGUAGE plpgsql;

-- 分割数が10、100、500、1000のパーティションを作成する
SELECT create_partition_traditional('traditional_0010', 10);
SELECT create_partition_traditional('traditional_0100', 100);
SELECT create_partition_traditional('traditional_0500', 500);
SELECT create_partition_traditional('traditional_1000', 1000);

-- 各分割数のパーティション上でクエリのEXPLAIN ANALYZEを実行し、プラン生成時間を確認する
EXPLAIN ANALYZE SELECT * FROM traditional_0010_0000009 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM traditional_0010 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM traditional_0100 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM traditional_0500 WHERE key = 9;
EXPLAIN ANALYZE SELECT * FROM traditional_1000 WHERE key = 9;

各パターン、5回ずつEXPLAIN ANALYZEを実行したときのプラン生成時間の中間値は以下のとおり。

項番 パターン プラン生成時間(ms)
1 パーティション分割しない 0.054
2 10パーティションに分割 0.202
3 100パーティションに分割 1.425
4 500パーティションに分割 74.960
5 1000パーティションに分割 158.204

従来のパーティショニング機能でも、パーティション数が多いほどプラン生成時間が長くなることを確認できる。

13
8
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
13
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?