PostgreSQL では、パーティション化は増え続けるデータを処理するための効果的な方法であり、パーティションプルーニングによってクエリが高速化されます。PolarDB for PostgreSQL (Compatible with Oracle) は、パーティションテーブル上の IMCI もサポートしており、パーティション化されたデータに対する統計および分析要件をさらに満たします。
背景情報
ビジネスシステムの継続的な運用に伴い、履歴データが蓄積され、テーブルはますます大きくなります。一般的な手法は、時間や user_id などのディメンションでデータをパーティション化し、各パーティションがデータのサブセットのみを保持するようにすることです。データをクエリする際、ネイティブ PostgreSQL もパーティションプルーニングを使用して、関連のないデータの読み取りを回避します。
PolarDB for PostgreSQL (Compatible with Oracle) の IMCI は、パーティションテーブルに対する分析クエリも高速化します。既存のパーティションテーブル上のインデックスと同じ方法で使用します。
結果
並列度 4 の場合、3 つのテストクエリすべてにおいて、IMCI はネイティブ PostgreSQL の並列実行よりも 35 倍以上高速です。
|
クエリ |
ネイティブ PostgreSQL の並列実行 |
IMCI |
|
Q1 |
2.13秒 |
0.05秒 |
|
Q2 |
6.42秒 |
0.18秒 |
|
Q3 |
10.51秒 |
0.30秒 |
操作手順
ステップ1:環境の準備
-
クラスターのバージョンと設定が次の要件を満たしていることを確認します。
-
クラスターのバージョン:
Oracle 構文互換性 2.0 (マイナーエンジンバージョン 2.0.14.10.20.0 以降)
説明コンソールで、または
SHOW polardb_version;ステートメントを実行してマイナーエンジンバージョンを確認できます。マイナーエンジンバージョンが要件を満たさない場合は、マイナーエンジンバージョンをアップグレードしてください。 -
wal_levelパラメーターをlogicalに設定する必要があります。この設定は、ロジカルデコーディングに必要な情報を先行書き込みログ (WAL) に追加します。説明コンソールでwal_level パラメーターを設定することができます。このパラメーターを変更するとクラスターが再起動されるため、ビジネスへの影響を考慮し、慎重に操作を行ってください。
-
ソーステーブルにはプライマリキーが必要で、列ストアインデックスの作成時にはそのプライマリキー列を含める必要があります。プライマリキーに
SERIALまたはBIGSERIALデータ型を使用すると、データ同期の効率が大幅に向上するため、推奨します。 -
各テーブルに作成できる列ストアインデックスは 1 つだけです。
-
-
IMCI 機能を有効にします。
IMCI を有効化する方法は、 または PolarDB for PostgreSQL (Compatible with Oracle) クラスターのマイナーエンジンバージョンによって異なります。
ステップ2:データの準備
この例では、多段パーティション化テーブルを作成し、約 3億2000万行 (~16 GB) のシミュレーションデータを挿入し、パーティション条件に基づいて統計分析を実行します。
テスト用のパーティションテーブルのスキーマは次のとおりです。
-
sales: プライマリテーブル。 -
sales_2023:年別にパーティション分割されています。-
sales_2023_a: 月別にパーティション化され、1 月から 6 月がパーティション a として定義されています。 -
sales_2023_b: 月単位でパーティション分割されており、7 月~12 月がパーティション b として定義されています。
-
-
sales_2024: 年別にパーティション化されています。-
sales_2024_a: 月単位でパーティション化され、1月から6月がパーティション a として定義されます。 -
sales_2024_bは、月別にパーティション分割されており、7月から12月がパーティション b として定義されています。
-
-
時間列
sale_dateをパーティションキーとして、salesという名前の多階層パーティションテーブルを作成します。定義は次のとおりです。CREATE TABLE sales ( sale_id serial, product_id int NOT NULL, sale_date date NOT NULL, amount numeric(10,2) NOT NULL, primary key(sale_id, sale_date) ) PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-1-1') TO ('2024-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023_a PARTITION OF sales_2023 FOR VALUES FROM ('2023-1-1') TO ('2023-7-1'); CREATE TABLE sales_2023_b PARTITION OF sales_2023 FOR VALUES FROM ('2023-7-1') TO ('2024-1-1'); CREATE TABLE sales_2024 PARTITION OF sales FOR VALUES FROM ('2024-1-1') TO ('2025-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2024_a PARTITION OF sales_2024 FOR VALUES FROM ('2024-1-1') TO ('2024-7-1'); CREATE TABLE sales_2024_b PARTITION OF sales_2024 FOR VALUES FROM ('2024-7-1') TO ('2025-1-1'); -
データを生成し、パーティションテーブルに挿入します (約 16 GB)。
INSERT INTO sales (product_id, sale_date, amount) SELECT (random()*100)::int AS product_id, '2023-01-1'::date + i/3200000*7 AS sale_date, (random()*1000)::numeric(10,2) AS amount FROM generate_series(1, 320000000) i; -
テーブルに、
sale_id、product_id、sale_date、およびamount列を含む IMCI を作成します。CREATE INDEX ON sales USING CSI(sale_id, product_id, sale_date, amount);
ステップ3:クエリの実行
異なる実行エンジンを使用してクエリを実行します。異なるパーティション条件に基づいて 3 つのクエリ (Q1、Q2、Q3) が生成されます。
-
IMCI を使用します。
--- IMCIを有効にし、クエリの並列度を4に設定します。 SET polar_csi.enable_query to on; SET polar_csi.exec_parallel to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date; -
IMCI を無効にし、ローストアエンジンを使用します。
--- IMCIを無効にし、ローストアエンジンを使用し、クエリの並列度を4に設定します。 SET polar_csi.enable_query to off; SET max_parallel_workers_per_gather to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale-date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date;