データベースでは、インデックスを作成することでクエリ性能を向上させることができます。データテーブル内のデータ量が増大するにつれて、パーティション分割によりデータテーブルを複数のシャードに分割し、ロードバランシングを利用してデータシャードをクラスタ全体に分散させることで、クラスタ全体のサービス能力を高めることができます。本記事では、ローカルインデックス、グローバルインデックス、一意インデックスについて主に説明します。
インデックスの種類
OceanBaseデータベースには、主に以下のインデックスタイプがあります:
ローカルパーティションインデックス:インデックス作成時にキーワード
LOCALを指定したインデックスはローカルインデックスであり、ローカルインデックスではパーティションルールを指定する必要はありません。そのパーティション属性はメインテーブルの属性と一致し、メインテーブルのパーティション操作に伴って変更されます。グローバルパーティションインデックス:インデックス作成時にキーワード
GLOBALを指定したインデックスはグローバルインデックスであり、グローバルインデックスはパーティションルールに基づいてテーブルを分割できます。一意インデックス:インデックスキー値が一意であることを示し、キーワード
UNIQUEで表されます。プレフィックスインデックス:パーティションインデックステーブルのパーティションキーがインデックス列の左側のプレフィックスである場合、このインデックスはプレフィックスインデックスと呼ばれます。これはMySQLの長い文字列のプレフィックスインデックスとは異なります。例えば、インデックステーブル
idxがc1とc2の列に基づいて構築されている場合、このインデックステーブルのパーティションキーがc1であれば、このインデックスはプレフィックスインデックスと呼ばれます。一方、インデックステーブルのパーティションキーがc2または他の列である場合は、プレフィックスインデックスではありません。プレフィックス以外のインデックス:パーティションプレフィックスインデックスと対照的に、パーティションインデックスがプレフィックスインデックスでない場合、それはプレフィックス以外のインデックスと呼ばれます。
ローカルインデックス
ローカルインデックスは、パーティションキーに基づいてローカルプレフィックスインデックスとローカルプレフィックス以外のインデックスに分類されます。
ローカルプレフィックスインデックス
パーティションキーがインデックスの左側のプレフィックスであり、かつインデックスにサブパーティションキーが含まれている場合、このインデックスはローカルプレフィックスインデックスです。ローカルプレフィックスインデックスは一意インデックスまたは非一意インデックスにすることができます。
インデックスキーを指定したクエリは、ローカルプレフィックスインデックスを使用して、インデックスパーティションを一意に特定でき、結果セットが比較的小さいがパーティションカットが必要な場合に非常に適しています。
例えば、テーブルAにローカルインデックスidx(c1,c2,c3)があり、メインテーブルはc1に基づいてパーティション化されています。ローカルインデックスの特性により、インデックステーブルとメインテーブルのパーティション方式は同じであり、したがってidxもc1をパーティションキーとしています。定義からわかるように、これはローカルプレフィックスインデックスです。指定されたインデックスキーを持つクエリを処理する際には、パーティションキーc1の値を使用して、唯一のインデックスパーティションを特定でき、インデックスパーティションへのアクセスを大幅に削減できます。
ローカルプレフィックス以外のインデックス
インデックステーブルがローカルプレフィックスインデックスでない場合、それはローカルプレフィックス以外のインデックスです。可能性のある状況としては、インデックステーブルのパーティションキーがインデックスの左側のプレフィックスではない、またはインデックスにサブパーティションキーが含まれていない場合があります。
パーティションキーがインデックスの部分集合でない場合、ローカルプレフィックス以外のインデックスは一意インデックスにすることができません。 インデックスキーを指定したクエリは、ローカルプレフィックス以外のインデックスを使用して、インデックスパーティションを特定できず、すべてのインデックスパーティションにアクセスする必要があるため、データ量が大きく、並行処理を重視するシナリオに適しています。
例えば、テーブルAにローカルインデックスidx(c1,c2,c3)があり、メインテーブルはc4列に基づいてパーティション化されています。定義からわかるように、これはローカルプレフィックス以外のインデックスです。ユーザーが指定されたインデックスキーをクエリする場合、パーティションキーを使用してインデックスパーティションを特定できないため、結果を取得するためにすべてのインデックスパーティションにアクセスする必要があります。このようなシナリオでは、並行実行が重要な役割を果たすことができます。
グローバルインデックス
グローバルインデックスは独自のパーティション定義を持ち、メインテーブルとは異なります。同時に、グローバルインデックステーブルのパーティションは分割および統合を行うこともできます。 一般的に、メインテーブルとグローバルインデックスのパーティション方式が完全に同じ場合、一意性を持つプレフィックス以外のインデックスを除き、他のインデックスはローカルインデックスとして定義することを推奨します。グローバルインデックスは、パーティション管理および保守に関するコストがローカルインデックスよりもはるかに高く、クエリコストやパーティションカットの観点から見ると、同じパーティション方式を持つグローバルインデックスとローカルインデックスの効果は同じです。
グローバルプレフィックスインデックス
グローバルパーティションインデックスの最初のフィールドはテーブルのメインパーティションフィールドであり、このインデックスはグローバルプレフィックスインデックスです。
グローバルプレフィックスインデックスは一意インデックスまたは非一意インデックスにすることができます。
グローバルプレフィックスインデックスはRangeパーティションでのみ意味を持ち、Hashパーティションインデックスには意味がありません。その理由は、ユーザーがHashパーティションインデックスを選択した場合、ユーザーのクエリモードは必ず指定されたインデックスキーによるポイントルックアップクエリであり、インデックスキーがパーティションキーをカバーしている場合、プレフィックスインデックスであるかどうかは意味がなく、ユーザーが指定したインデックスキー値に基づいてインデックスパーティションを計算できるためです。ユーザーがすべてのパーティションキー値を指定しない場合、Hashパーティションインデックスはすべてのパーティションデータにアクセスする必要がありますが、Rangeパーティションは一定程度のパーティションカットを行うことができます。
グローバルプレフィックス以外のインデックス
OceanBaseデータベースはグローバルプレフィックス以外のインデックスをサポートしておらず、グローバルプレフィックス以外のインデックスはクエリの最適化にあまり意味がありません。
例えば、テーブルAにグローバルインデックスidx(c1,c2)があり、idxはc2に基づいてパーティション化されている場合、idxはグローバルプレフィックス以外のインデックスです。この場合、ユーザーがすべてのインデックスキー値を指定した場合にのみパーティションカットを行うことができ、その他の場合はすべてのインデックスパーティションをスキャンする必要があるため、ユーザーはc1キーを直接使用してパーティション化する理由がありません。c1を使用すると、プレフィックスフィルタリングによるパーティションカットも可能です。
一意インデックス
一意インデックスはグローバルインデックスまたはローカルインデックスとして定義できます。
一意インデックスをローカルインデックスとして定義する場合、一定の条件を満たす必要があります。つまり、インデックスキーはインデックスパーティションキーをカバーしている必要があります。 例えば、テーブルAに一意インデックスidx(c1,c2,c3)があり、インデックステーブルidxは(c1,c2)に基づいてパーティション化されています。これにより、同じ(c1,c2)は常に同一のパーティションに入ることが保証され、単一のパーティション内での一意性のみを維持する必要があります。インデックステーブルidxが(c2,c4)に基づいてパーティション化され、インデックスがパーティションキーをカバーしていない場合、ローカルインデックスを使用してパーティション間のインデックスキーの一意性を保証することはできず、このようなローカル一意インデックスは作成できません。
インデックス作成ポリシー
インデックスを作成する際には、ユーザーのクエリパターン、インデックス管理、パフォーマンス、可用性などのニーズを総合的に考慮し、自社業務に最も適したインデックス方式を選択する必要があります。
ユーザーが一意のインデックスを必要とし、かつインデックスキーがすべてのパーティションキーをカバーしている場合は、ローカルインデックスとして定義できます。そうでない場合は、グローバルインデックスを使用する必要があります。
主表のパーティションキーがインデックスの部分集合である場合は、ローカルインデックスを使用できます。
主表のパーティション属性とインデックスのパーティション属性が同じ場合は、ローカルインデックスを使用することを推奨します。
ユーザーがインデックスパーティション管理のコストを重視し、主表のパーティションが常に削減され続ける場合は、グローバルインデックスの作成を避けるようにしてください。これは、主表のパーティション削減操作によりグローバルインデックスの変更が大きくなり、回復が困難になる可能性があるためです。また、インデックスが利用不可能になる可能性もあります。
ユーザーのクエリが常にすべてのインデックスパーティションキー値を指定する場合は、パーティションキーを含む必要はなく、他の列にのみインデックスを作成することで、メンテナンスコストとストレージコストを削減できます。パーティションキーを指定しないクエリでは、プレフィックス付きインデックスはパーティションカットやデータ量が比較的小さいシナリオに適しており、プレフィックスなしインデックスは一般的にパーティション並列処理やデータ量が比較的大きいシナリオに適しています。
パーティション選択ポリシー
インデックスパーティションを行う際、単一のインデックステーブルのデータ量が非常に大きい場合は、パーティション分割を行う必要があります。これにより、クエリのパーティション並列処理や負荷分散がより効果的になります。
ユーザーのクエリがインデックスキーを指定した単一ポイント・ルックアップ・クエリが多い場合、アクセスするパーティション数とアクセスの同時実行の観点から見ると、HashパーティションとRangeパーティションのクエリコストに大きな違いはありません。ただし、データにホットスポットが存在する場合は、Hashパーティションを使用することでホットスポット問題をより効果的に回避できます。
ユーザーのクエリがインデックスキーを指定した範囲クエリが多い場合、アクセスするパーティション数の観点からはRangeパーティションの方がHashパーティションよりも優れています。しかし、同時実行の観点から見ると、Hashパーティションの方が並行クエリの利点をより効果的に活用でき、クエリ結果セットが非常に大きい場合、Hashパーティションの並行クエリの方がより大きなパフォーマンスの利点を得られるはずです。
クエリ時のインデックス選択ポリシー
ユーザーがパーティションカットを重視する場合は、プレフィックス付きインデックスを選択する方が良いでしょう。クエリフィルタ条件でパーティションプレフィックスの値を指定することで、パーティションカットを最大限に行い、インデックスパーティションデータの読み取りを削減できます。
ユーザーがスループットを重視し、アクセスするデータ量が比較的大きい場合は、プレフィックスなしインデックスを選択する方がパフォーマンスを向上させることができます。パーティション並列処理を通じてパーティションキー上の範囲クエリを解決できます。ローカルプレフィックスなしインデックスはすべてのパーティションへの同時アクセスが可能ですが、ローカルプレフィックス付きインデックスはパーティションカットを行い、少数のパーティションで大量のデータセットを処理するため、応答時間は並行クエリよりも劣る可能性があります。