sql >> データベース >  >> RDS >> PostgreSQL

パーティションごとの結合のための高度なパーティションマッチング

    以前、PostgreSQLでのパーティション単位の結合に関するブログを書きました。そのブログでは、パーティションごとの結合をより多くの場合に使用できるようにする高度なパーティションマッチング手法について話しました。このブログでは、この手法について詳しく説明します。

    要約すると、基本的なパーティションマッチング手法では、2つのパーティションテーブルが完全に一致するパーティション境界を持っている場合、パーティションごとの結合手法を使用して2つのパーティションテーブル間の結合を実行できます。以下で説明するパーティションテーブルprt1とprt2

    psql>\d+ prt1
    ... [output clipped]
    Partition key: RANGE (a)
    Partitions: prt1_p1 FOR VALUES FROM (0) TO (5000),
    prt1_p2 FOR VALUES FROM (5000) TO (15000),
    prt1_p3 FOR VALUES FROM (15000) TO (30000)

    および

    psql>\d+ prt2
    ... [ output clipped ]
    Partition key: RANGE (b)
    Partitions: prt2_p1 FOR VALUES FROM (0) TO (5000),
    prt2_p2 FOR VALUES FROM (5000) TO (15000),
    prt2_p3 FOR VALUES FROM (15000) TO (30000)

    パーティションキー(a)でのprt1とprt2の間の結合は、一致するパーティション間の結合に分割されます。つまり、prt1_p1はprt2_p1に結合し、prt1_p2はprt2_p2に結合し、prt1_p3はprt2_p3に結合します。これらの3つの結合の結果は、prt1とprt2の間の結合の結果を形成します。以前のブログで説明したように、これには多くの利点があります。ただし、基本的なパーティションマッチングでは、パーティション境界が異なる2つのパーティションテーブルを結合することはできません。上記の例で、prt1に追加のパーティションprt1_p4 FOR VALUES FROM(30000)TO(50000)がある場合、基本的なパーティションマッチングは、prt1とprt2の間の結合を、完全に一致するパーティションがないため、パーティションごとの結合に変換するのに役立ちません。境界。

    多くのアプリケーションは、パーティションを使用して、アクティブに使用されているデータと古いデータを分離します。これは、別のブログで説明した手法です。古いデータは、パーティションを削除することで最終的に削除されます。新しいパーティションは、新しいデータに対応するために作成されます。このような2つのパーティション化されたテーブル間の結合では、ほとんどの場合、一致するパーティションがあるため、パーティションごとの結合が使用されます。ただし、アクティブなパーティションがこれらのテーブルの1つに追加されたり、古いパーティションが削除されたりすると、他のテーブルも同様の操作を実行するまで、それらのパーティションの境界は一致しません。その間隔の間、これら2つのテーブル間の結合はパーティション単位の結合を使用せず、実行に異常に長い時間がかかる場合があります。パーティション単位の結合を使用できないため、この短い期間にデータベースにヒットする結合のパフォーマンスが低下することは望ましくありません。高度なパーティションマッチングアルゴリズムは、パーティションの境界が正確に一致しないこのような、より複雑なケースで役立ちます。

    高度なパーティションマッチングアルゴリズム

    高度なパーティションマッチング技術は、パーティションの境界が完全に一致していない場合でも、2つのパーティションテーブルから一致するパーティションを検出します。マージ結合アルゴリズムと同様に、並べ替えられた順序で両方のテーブルの境界を比較することにより、一致するパーティションを見つけます。境界が完全に一致するか重複する、各パーティションテーブルからの2つのパーティションは、結合行が含まれている可能性があるため、結合パートナーと見なされます。上記の例を続けて、アクティブな新しいパーティションprt2_p4がprt4に追加されたとします。パーティション化されたテーブルは次のようになります。

    psql>\d+ prt1
    ... [output clipped]
    Partition key: RANGE (a)
    Partitions: prt1_p1 FOR VALUES FROM (0) TO (5000),
    prt1_p2 FOR VALUES FROM (5000) TO (15000),
    prt1_p3 FOR VALUES FROM (15000) TO (30000)

    および

    psql>\d+ prt2
    ... [ output clipped ]
    Partition key: RANGE (b)
    Partitions: prt2_p1 FOR VALUES FROM (0) TO (5000),
    prt2_p2 FOR VALUES FROM (5000) TO (15000),
    prt2_p3 FOR VALUES FROM (15000) TO (30000),
    prt2_p4 FOR VALUES FROM (30000) TO (50000)

    prt1_p1とprt2_p1、prt1_p2とprt2_p2、およびprt1_p3とprt2_p3のパーティション境界がそれぞれ一致していることは簡単にわかります。ただし、基本的なパーティションマッチングとは異なり、高度なパーティションマッチングでは、prt2_p4に一致するパーティションがprt1にないことがわかります。 prt1とprt2の間の結合が内部結合である場合、またはprt2が結合の内部関係である場合、結合結果にはprt2_p4からの行がありません。一致するパーティションと一致しないパーティションに関する詳細情報を有効にすると、パーティションの境界が一致するかどうかだけでなく、クエリオプティマイザーはパーティションごとの結合を使用するかどうかを決定できます。この場合、prt2_p4を残して、一致するパーティション間の結合として結合を実行することを選択します。ただし、これは「高度な」パーティションマッチングとはあまり異なります。今回はリストパーティションテーブルを使用したもう少し複雑なケースを見てみましょう:

    psql>\d+ plt1
    Partition key: LIST (c)
    Partitions: plt1_p1 FOR VALUES IN ('0001', '0003'),
    plt1_p2 FOR VALUES IN ('0004', '0006'),
    plt1_p3 FOR VALUES IN ('0008', '0009')

    および

    psql>\d+ plt2
    Partition key: LIST (c)
    Partitions: plt2_p1 FOR VALUES IN ('0002', '0003'),
    plt2_p2 FOR VALUES IN ('0004', '0006'),
    plt2_p3 FOR VALUES IN ('0007', '0009')

    両方の関係に正確に3つのパーティションがあるが、パーティション値リストが異なることに注意してください。パーティションplt1_p2に対応するリストは、plt2_p2のリストと完全に一致します。それ以外は、どちらかの側から1つずつ、2つのパーティションに完全に一致するリストがありません。高度なパーティションマッチングアルゴリズムは、plt1_p1とplt2_p1のリストが重複しており、それらのリストが他のリレーションの他のパーティションと重複していないことを前提としています。同様に、plt1_p3とplt2_p3についても同様です。次に、クエリオプティマイザは、一致するパーティション(plt1_p1とplt2_p1、plt1_p2、plt2_p2、plt1_p3とplt2_p3)をそれぞれ結合することにより、plt1とplt2の間の結合をパーティションごとの結合として実行できることを確認します。アルゴリズムは、リストのさらに複雑なパーティションバインドセットおよび範囲パーティションテーブルで一致するパーティションを見つけることができます。ただし、簡潔にするためにそれらについては説明しません。興味があり、より大胆な読者は、コミットを見てみるかもしれません。また、高度なパーティションマッチングアルゴリズムが使用されるさまざまなシナリオを示す多くのテストケースがあります。

    制限

    内側で一致するパーティションが欠落している外部結合

    外部結合は、PostgreSQLの世界で特定の問題を引き起こします。上記の例で、prt2 LEFT JOIN prt1について考えてみます。ここで、prt2はOUTER関係です。 prt2_p4にはprt1に結合パートナーがありませんが、そのパーティションの行は外部リレーションに属しているため、結合結果の一部である必要があります。 PostgreSQLでは、結合の内側が空の場合、行を出力しないがその関係のスキーマを認識している「ダミー」関係で表されます。通常、「ダミー」リレーションは、制約の除外などのクエリ最適化のために行を出力しない非ダミーリレーションから発生します。 PostgreSQLのクエリオプティマイザは、このような非ダミーの関係をダミーとしてマークし、エグゼキュータはそのような結合を実行するときに正常に続行します。ただし、外部パーティションに一致する内部パーティションがない場合、「ダミー」としてマークできる「既存のエンティティ」はありません。たとえば、この場合、外部prt2_p4を結合するダミーの内部パーティションを表すことができるprt1_p4はありません。現在、PostgreSQLには、計画中にそのような「ダミー」の関係を「作成」する方法がありません。したがって、この場合、クエリオプティマイザはパーティション単位の結合を使用しません。

    理想的には、このような空の内部との結合には、内部関係のスキーマのみが必要であり、関係全体は必要ありません。このスキーマは、パーティションテーブル自体から派生させることができます。必要なのは、内側の列のNULL値で結合された外側の行の列を使用して結合行を生成する機能だけです。 PostgreSQLでその機能を使用できるようになると、クエリオプティマイザはこれらの場合でもパーティション単位の結合を使用できるようになります。

    内側の結合に欠落しているパーティションがない外側の結合は、パーティションごとの結合を使用することを強調しておきます。

    複数の一致するパーティション

    片側の複数のパーティションが反対側の1つ以上のパーティションと一致するようにテーブルがパーティション化されている場合、計画時に2つ以上を表す「追加」関係を誘導する方法がないため、パーティションごとの結合は使用できません。一緒にパーティションします。うまくいけば、いつかその制限を取り除き、そのような場合にもパーティション単位の結合を使用できるようにする予定です。

    パーティションテーブルをハッシュする

    同じモジュロを使用する2つのハッシュパーティションテーブルのパーティション境界は常に一致します。モジュロが異なる場合、一方のテーブルの特定のパーティションの行は、もう一方のパーティションの多くに結合パートナーを持つ可能性があります。したがって、一方のパーティションが他方のテーブルの複数のパーティションと一致するため、パーティションごとの結合が無効になります。

    高度なパーティションマッチングアルゴリズムが一致するパーティションを見つけられない場合、または上記の制限のためにパーティションごとの結合を使用できない場合、PostgreSQLはフォールバックしてパーティションテーブルを通常のテーブルとして結合します。

    高度なパーティションマッチング時間

    サイモンは、この機能についてコメントするときに興味深い点を指摘しました。パーティションテーブルのパーティションは頻繁に変更されないため、高度なパーティションマッチングの結果は、長期間同じままである必要があります。これらのテーブルを含むクエリが実行されるたびに計算する必要はありません。代わりに、一致するパーティションのセットをカタログに保存し、パーティションが変更されるたびに更新することができます。これは多少の作業ですが、すべてのクエリのパーティションを照合するのに時間をかける価値があります。

    これらすべての制限があっても、今日私たちが持っているのは、ほとんどの実際的なケースに役立つ非常に便利なソリューションです。言うまでもなく、この機能はFDW参加プッシュダウンとシームレスに連携し、PostgreSQLがすでに備えているシャーディング機能を改善します!


    1. SQLOPSを使用してSQLServerデータベースを作成する

    2. MySQLトリガーは、トリガーが割り当てられている同じテーブルの行を更新できません。推奨される回避策は?

    3. SQL Serverでデータアクセスを有効/無効にする方法(T-SQLの例)

    4. PostgreSQLデータベース内のサイズ(相対および絶対)のスキーマのリスト