このトピックでは、PartitionedTableScan機能について説明し、その背景、使用方法、およびパフォーマンス改善に関する統計情報を提供します。
背景情報
では、テーブルのパーティション数が制限されないため、サブパーティショニングではパーティション数が指数関数的に増加します。
例えば、テーブルが100のパーティションにハッシュ分割され、次に各パーティションが100のサブパーティションにハッシュ分割される場合、このパーティション分割されたテーブルには合計10,000のパーティションが存在することになる。 このテーブルに対してクエリを実行すると、実行計画は次のようになります。
part_hashからselect * の分析を説明します。
クエリ計画
-----------------------------------------------------------------------------
追加 (コスト=0.00 .. 344500.00行=16300000幅=22)
-> part_hash_sys0102のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
-> part_hash_sys0103のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
-> part_hash_sys0104のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
...
...
...
-> part_hash_sys10198のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
-> part_hash_sys10199のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
-> part_hash_sys10200のSeqスキャン (コスト=0.00 .. 26.30行=1630幅=22)
計画時間: 3183.644 ms
実行時間: 633.779 ms
(10003行)
総メモリ: 216852KB
計画に示されているように、クエリの完了には長い時間がかかります。これは、オプティマイザがパーティションテーブルの実行計画を生成する方法に関連しています。 パーティションテーブルが少数のパーティションしか有していない場合、プロセスは高速であり、満足なユーザエクスペリエンスを提供する。 ただし、パーティションの数が増えると、プロセスが遅くなり、パーティション分割されていないテーブルよりもパーティション分割されたテーブルのパフォーマンスが悪くなることがあります。
たとえば、前のクエリでは、テーブルのpart_hash
に10,000のパーティションがあります。 その計画時間は3秒に達しました。 対照的に、テーブルが分割されていない場合、このクエリの計画時間は約0.1ミリ秒になります。 長い計画時間に加えて、パーティション分割テーブルのクエリでは、メモリ使用量が多くなり、OOMの問題が発生する可能性があります。
パーティション分割テーブルのこの欠点は、次のクエリプランに示すように、結合がクエリに含まれる場合にさらに悪化します。
create table part_hash2 (a int, b int, c varchar (10))
PARTITION by HASH(a) SUBPARTITION by HASH (b) PARTITIONS 100 SUBPARTITIONS 100;
a.a=b.bでpart_hash a join part_hash2 bから選択カウント (*) を分析すると説明します。b.c = '0001';
クエリ計画
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
集計の完了 (コスト=48970442.90 .. 48970442.91行=1幅=8) (実際の時間=6466.854 .. 6859.935行=1ループ=1)
-> 収集 (コスト=48970442.68 .. 48970442.89行=2幅=8) (実際の時間=397.780 .. 6859.902行=3ループ=1)
Workers Planned: 2
労働者の立ち上げ: 2
-> 部分集計 (コスト=48969442.68 .. 48969442.69行=1幅=8) (実際の時間=4.748 .. 11.768行=1ループ=3)
-> マージ結合 (コスト=1403826.01 .. 42177776.01行=2716666667幅=0) (実際の時間=4.736 .. 11.756行=0ループ=3)
結合: (a.a = b.b)
-> 並べ替え (コスト=1093160.93 .. 1110135.93行=6790000幅=4) (実際の時間=4.734 .. 8.588行=0ループ=3)
ソートキー: a.a
ソート方法: quicksortメモリ: 25kB
ワーカー0: ソート方法: quicksortメモリ: 25kB
ワーカー1: ソート方法: quicksortメモリ: 25kB
-> 並列追加 (コスト=0.00 .. 229832.35行=6790000幅=4) (実際の時間=4.665 .. 8.518行=0ループ=3)
-> Parallel Seq part_hash_sys0102aでスキャン (コスト=0.00 .. 19.59行=959幅=4) (実際の時間=0.001 .. 0.001行=0ループ=1)
-> Parallel Seq part_hash_sys0103 a_1でスキャン (コスト=0.00 .. 19.59行=959幅=4) (実際の時間=0.001 .. 0.001行=0ループ=1)
-> Parallel Seq part_hash_sys0104 a_2でスキャン (コスト=0.00 .. 19.59行=959幅=4) (実際の時間=0.001 .. 0.001行=0ループ=1)
...
-> 並べ替え (コスト=310665.08 .. 310865.08行=80000幅=4) (実行されない)
ソートキー: b.b
-> 追加 (コスト=0.00 .. 304150.00行=80000幅=4) (実行されない)
-> Seq part_hash2_sys0102 bのスキャン (コスト=0.00 .. 30.38行=8幅=4) (実行されない)
フィルター: ((c)::text = '0001'::text)
-> part_hash2_sys0103 b_1のSeqスキャン (コスト=0.00 .. 30.38行=8幅=4) (実行されない)
フィルター: ((c)::text = '0001'::text)
-> part_hash2_sys0104 b_2のSeqスキャン (コスト=0.00 .. 30.38行=8幅=4) (実行されない)
フィルター: ((c)::text = '0001'::text)
...
計画時間: 221082.616 ms
実行時間: 9500.148 ms
(30018行)
総メモリ: 679540KB
したがって、スキャンされたデータを特定のパーティションに限定することができないクエリの場合、パーティション分割されたテーブルは、非パーティション分割されたテーブルよりもパフォーマンスが悪い場合があります。 パーティションプルーニングはパーティションを特定するのに役立ちますが、一部のOLAPシナリオではフルテーブルスキャンが必要な場合があるため、これはすべて解決策ではありません。
解決策
多数のパーティションを持つテーブルに対する長期クエリの問題を解決するために、はPartitionedTableScan
演算子を提供しています。 追加演算子を使用する場合と比較して、効率が高く、計画時間が短く、メモリ使用量が少なくなります。
PartitionedTableScan
を使用すると、2つのSQL文が実行され、計画時間とメモリ消費が大幅に削減されます。
part_hashからselect * の分析を説明します。
クエリ計画
----------------------------------------------------------------------------------------------------------------------------------------------------
part_hashのPartitionedTableScan (コスト=0.00 .. 1.00行=1幅=22) (実時間=134.348 .. 134.352行=0ループ=1)(反復パーティション番号10000)
スキャンパーティション: part_hash_sys0102、part_hash_sys0103、。.. part_hash_sys10198, part_hash_sys10199, part_hash_sys10200
-> part_hashのSeqスキャン (コスト=0.00 .. 1.00行=1幅=22)
計画時間: 293.778 ms
実行時間: 384.202 ms
(5行)
総メモリ: 40276KB
a.a=b.bでpart_hash a join part_hash2 bから選択カウント (*) を分析すると説明します。b.c = '0001';
クエリ計画
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
集計 (コスト=2.02 .. 2.03行=1幅=8) (実際の時間=152.322 .. 152.326行=1ループ=1)
-> ネストされたループ (コスト=0.00 .. 2.02行=1幅=0) (実際の時間=152.308 .. 152.311行=0ループ=1)
参加フィルター :( a.a = b.b)
-> part_hashのPartitionedTableScan (コスト=0.00 .. 1.00行=1幅=4) (実際の時間=152.305 .. 152.306行=0ループ=1)(反復パーティション数10000)
スキャンパーティション: part_hash_sys0102, part_hash_sys0103, part_hash_sys10198, part_hash_sys10199, part_hash_sys10200
-> Seq part_hash aのスキャン (コスト=0.00 .. 1.00行=1幅=4)
-> part_hash2 bのPartitionedTableScan (コスト=0.00 .. 1.00行=1幅=4) (実行されない)
-> part_hash2 bのSeqスキャン (コスト=0.00 .. 1.00行=1幅=4)
フィルター: ((c)::text = '0001'::text)
計画時間: 732.952 ms
実行時間: 436.927 ms
(11行)
総メモリ: 68104KB
次の表に比較を示します。
項目 |
|
|
単一クエリ計画時間 | 3183.644ms | 293.778ms |
シングル総メモリ | 216852 KB | 40276 KB |
クエリ計画時間に参加する | 221082.616ms | 732.952ms |
総メモリに参加する | 679540 KB | 68104 KB |
制限事項
PartitionedTableScan
を使用して実行できるのは、SELECT
コマンドのみです。 DMLステートメントはサポートされていません。PartitionedTableScan
をパーティション単位の結合と一緒に使用することはできません。 パーティションごとの結合機能が有効になっている場合、実行計画にはPartitionedTableScan
演算子は含まれません。
リビジョンバージョンがV1.1.32より前のクラスターに対してPartitionedTable Scan
を有効にする場合は、テクニカルサポートにお問い合わせください。
手順
このセクションでは、例を使用してPartitionedTableScan
機能の使用方法を説明します。
デモ用に次のパーティションテーブルが作成されています。
CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY Hash(a) パーティション16;
PartitionedTableScanの有効化
PartitionedTableScan
機能を有効または無効にするには、polar_num_parts_for_partitionedscan
パラメーターを設定します。
パラメーター | 有効値 | デフォルト値 | 説明 |
polar_num_parts_for_partitionedscan | -1にINT_MAX | 64 |
パラメータには2つの特別な値があります。
|
例:
SET polar_num_parts_for_partitionedscanを-1にします。説明select * from prt1;
クエリ計画
-----------------------------------------------------------------
prt1のPartitionedTableScan (コスト=0.00 .. 1.00行=1幅=40)
-> Seqスキャンprt1 (コスト=0.00 .. 1.00行=1幅=40)
(2行)
ヒントの使用
ヒントPARTEDSCAN (テーブルエイリアス)
を使用して、PartitionedTableScanの使用を指示できます。 例:
EXPLAIN select /* + PARTEDSCAN(prt1) */ select * from prt1;
クエリ計画
-----------------------------------------------------------------
prt1のPartitionedTableScan (コスト=0.00 .. 1.00行=1幅=40)
-> Seqスキャンprt1 (コスト=0.00 .. 1.00行=1幅=40)
(2行)
PartitionedTableScan in parallel
には、大量のデータに対するクエリのパフォーマンスを向上させる並列追加機能があります。 parallel append
と同様に、PartitionedTableScan
も並行して実行できます。 機能の名前はPartitionedTableScan Append
です。 パーティション間モードとハイブリッドモードの2つの並列モードをサポートしています。
PartitionedTableScanパーティションに追加
このモードでは、各ワーカーがパーティションを処理し、並列に動作します。
EXPLAIN (COSTS OFF) select /* + PARTEDSCAN(prt1) */ * from prt1;
クエリ計画
---------------------------------------------
収集
Workers Planned: 4
-> Parallel PartitionedTableScan on prt1
-> Seqスキャンprt1
(4行)
上記のクエリプランでは、4つのワーカーが実行に使用され、それぞれが1つのパーティションで動作します。 クエリプランのParallel PartitionedTableScan
演算子は、このモードのインジケーターです。
Hybrid PartitionedTableScanの追加
ハイブリッドモードでは、システムは、パーティション内およびパーティション間の両方で並列に実行を処理します。
EXPLAIN (COSTS OFF) select /* + PARTEDSCAN(prt1) */ * from prt1;
クエリ計画
---------------------------------------------
収集
計画されている労働者: 8
-> Parallel PartitionedTableScan on prt1
-> パラレルSeqスキャンprt1
(4行)
この例では、8つのワーカーが使用されます。 このクエリプランには、Parallel PartitionedTableScan
インジケーターが含まれています。
各モードにはコストモデルがあり、オプティマイザはコストの低いモードを選択します。
パーティションの剪定
PartitionedTableScan
は、3つのステージすべてでパーティションプルーニングをサポートします。 パーティションプルーニングの詳細については、「パーティションプルーニング」をご参照ください。
パフォーマンステスト
PartitionedTableScan
はより高い効率を提供します。 このパフォーマンステストは、PartitionedTableScan
によって有効になっているパフォーマンスの改善を示します。
以下のテスト結果は開発環境からのものであり、参考のためだけに提供されています。 実際の結果は、異なる構成および条件に基づいて変化し得る。 テストは、PartitionedTableScan
のパフォーマンス改善効果をテストするために、一貫した環境構成で実行されます。 パーティションの数は唯一の変数です。
テストには次のSQL文が使用されます。
select * from prt1 b = 10;
select /* + PARTEDSCAN(prt1) */ * from prt1 b = 10;
単一のSQL文の計画時間
パーティション数 | 追加計画時間 | PartitionedTableScan計画時間 |
16 | 0.266ms | 0.067ms |
32 | 1.820ms | 0.258ms |
64 | 3.654ms | 0.402ms |
128 | 7.010ms | 0.664ms |
256 | 14.095ms | 1.247ms |
512 | 27.697ms | 2.328ms |
1024 | 73.176ms | 4.165ms |
単一のSQL文のメモリ使用量
パーティション数 | 追加メモリ | PartitionedTableScanメモリ |
16 | 1,170 KB | 1,044 KB |
32 | 1,240 KB | 1,044 KB |
64 | 2,120 KB | 1,624 KB |
128 | 2,244 KB | 1,524 KB |
256 | 2,888 KB | 2,072 KB |
512 | 4,720 KB | 3,012 KB |
1024 | 8,236 KB | 5,280 KB |
1秒あたりのクエリ (QPS)
pgbench -i -- scale=10
pgbench -c 64 -j 64 -n -T60
クエリ:
説明select * from prt1 b = 10;
select /* + PARTEDSCAN(prt1) */ * from prt1 b = 10;
パーティション数 | QPSの追加 | PartitionedTableScan QPS |
16 | 25,318 | 93,950 |
32 | 10,906 | 61,879 |
64 | 5,281 | 30,839 |
128 | 2,195 | 16,684 |
256 | 920 | 8,372 |
512 | 92 | 3,708 |
1024 | 21 | 1,190 |
結論
上記のパフォーマンステストの結果は、PartitionedTableScan
がパフォーマンスを大幅に改善できることを示しています。 ビジネスに関係するテーブルに多数のパーティションがあり、クエリの実行に時間がかかる場合は、パフォーマンスを向上させるためにPartitionedTableScan
を使用することをお勧めします。