PolarDB-Xはグローバルセカンダリインデックスをサポートしています。 このトピックでは、DRDSモードを使用してパーティション分割されたテーブルでグローバルセカンダリインデックスを作成および使用する方法について説明します。
使用上の注意
このトピックで説明したグローバルセカンダリインデックスの作成および使用方法は、自動パーティショニングモードを使用してパーティション化されたテーブルにも適用されます。 ただし、自動パーティション分割モードを使用してパーティション分割されたテーブルのグローバルセカンダリインデックスを作成するには、create INDEX ( DRDSモード) で説明されている構文を使用する必要があります。
注意
- テーブルのグローバルセカンダリインデックスを作成する前に、次の制限に注意する必要があります。
- シャードされていないテーブルまたはブロードキャストテーブルのグローバルセカンダリインデックスを作成することはできません。
- 一意のグローバルセカンダリインデックスはプレフィックスインデックスをサポートしていません。
- インデックステーブルを作成するときは、インデックスの名前を指定する必要があります。
- インデックステーブルを作成するときは、データベースシャーディングルール、またはデータベースシャーディングとテーブルシャーディングのルールを指定する必要があります。 テーブルシャーディングルールのみを指定することはできません。
- インデックステーブルのインデックスキーには、インデックステーブルのすべてのシャードキーを含める必要があります。
- インデックスキー列およびカバーリング列と同じ列を指定することはできません。
- 既定では、インデックステーブルには、ベーステーブルの主キー列とすべてのシャードキー列が含まれます。 主キーとシャードキーの列をインデックスキー列として指定しない場合、これらの列はデフォルトでカバー列として使用されます。
- DRDSモードのデータベースでは、ベーステーブルのローカルインデックスのすべてのインデックス列がインデックステーブルに含まれている場合、デフォルトでローカルインデックスがインデックステーブルに追加されます。
- グローバルセカンダリインデックスのインデックスキー列にローカルインデックスが作成されていない場合、グローバルセカンダリインデックスの各インデックスキー列にローカルインデックスが自動的に作成されます。
- 既定では、複合インデックスは、複数の列に作成されたグローバルセカンダリインデックスに対して作成されます。 複合インデックスは、グローバルセカンダリインデックスのすべてのインデックスキー列に適用されます。
- lengthパラメーターを使用して、ローカルインデックスの作成に使用するシャーディングキーのプレフィックスの長さのみを指定できます。
- テーブルのグローバルセカンダリインデックスを作成すると、グローバルセカンダリインデックスの作成後にデータが検証されます。 グローバルセカンダリインデックスの作成に使用されるDDLステートメントは、インデックステーブルのデータが検証された後にのみ実行できます。
説明 CHECK GLOBAL INDEXステートメントを使用して、インデックステーブルのデータを検証および修正できます。 - ALTER TABLEステートメントを使用してテーブルを管理する前に、次の情報に注意する必要があります。
ステートメント ベーステーブルのシャードキーの変更 主キーの変更 ローカルインデックスの一意の列の変更 インデックステーブルのシャードキーの変更 テーブルの一意インデックスの列の変更 インデックス列の変更 カバー列の変更 コラムを追加 N/A 非対応 N/A N/A N/A N/A N/A ALTER COLUMN SET DEFAULTおよびALTER COLUMN DROP DEFAULT 非対応 非対応 対応 非対応 非対応 非対応 非対応 コラムを変更する 非対応 非対応 対応 非対応 非対応 非対応 非対応 ドロップコラム 非対応 非対応 一意のインデックスが1つの列にのみ作成されている場合にのみサポートされます。 非対応 非対応 非対応 非対応 変更コラム 非対応 非対応 対応 非対応 非対応 非対応 非対応 次の表に、インデックスの管理に使用できるALTER tableステートメントを示します。説明- DROP COLUMNステートメントを使用して、グローバルセカンダリインデックスから列を削除することはできません。 グローバルセカンダリインデックスから列を削除すると、グローバルセカンダリインデックスのパフォーマンスがマイナスの影響を受ける可能性があります。 グローバルセカンダリインデックスの列を削除する場合は、DROP indexステートメントを使用してグローバルセカンダリインデックスを削除し、新しいグローバルセカンダリインデックスを作成します。
- 特定のシナリオでは、同じ列が前の表で説明されている異なる列タイプに属します。 たとえば、テーブルの同じシャードキー列がインデックス列とカバー列として使用されます。 同じ列がインデックステーブルの異なる型の列として使用されており、いずれかの列型で操作がサポートされていない場合、その列で操作を実行することはできません。
ステートメント 説明 ALTER TABLE ADD PRIMARYキー サポートされています。 ALTER TABLE ADD [UNIQUE/FULLTEXT/SPATIAL/FOREIGN] キー サポートされています。 このステートメントを使用して、ベーステーブルとインデックステーブルに同時にローカルインデックスを追加できます。 ローカルインデックスの名前は、グローバルセカンダリインデックスの名前と同じにすることはできません。 ALTER TABLE ALTER INDEX index_name {VISIBLE | INVISIBLE} サポートされていません。 ALTER TABLE {DISABLE | ENABLE} KEYS サポートされています。 このステートメントは、ベーステーブルでのみ使用できます。 このステートメントを使用して、グローバルセカンダリインデックスのステータスを変更することはできません。 ALTER TABLE DROP PRIMARYキー サポートされていません。 ALTER TABLEドロップインデックス この文を使用して、共通インデックスまたはグローバルセカンダリインデックスのみを削除できます。 ALTER TABLE DROP FOREIGNキーfk_symbol サポートされています。 このステートメントは、ベーステーブルでのみ実行できます。 ALTER TABLE RENAME INDEX サポートされていません。 説明 DROP COLUMNステートメントを使用して、グローバルセカンダリインデックスの名前を変更することはできません。 グローバルセカンダリインデックスの名前を変更すると、グローバルセカンダリインデックスのパフォーマンスがマイナスの影響を受ける可能性があります。 グローバルセカンダリインデックスの名前を変更する場合は、DROP indexステートメントを使用してグローバルセカンダリインデックスを削除し、新しいグローバルセカンダリインデックスを作成します。 - グローバルセカンダリインデックステーブルを管理する前に、次の制限に注意する必要があります。
- インデックステーブルでDDLまたはDMLステートメントを実行することはできません。
- NODEヒントを含むDMLステートメントを実行して、ベーステーブルまたはインデックステーブルを更新することはできません。
- グローバルセカンダリインデックスを含むテーブルでDDLステートメントを実行する前に、次の表に記載されている制限に注意する必要があります。
ステートメント 説明 DROP TABLE 対応 DROP INDEX 対応 TRUNCATE TABLE 非対応 RENAMEテーブル 非対応 ALTER TABLE RENAME 非対応 説明- ベーステーブルとベーステーブルのインデックステーブル間でデータの一貫性を確保するために、ベーステーブルまたはインデックステーブルでTRUNCATE table文を使用することはできません。 ベーステーブルおよびベーステーブルのインデックステーブルからデータを削除する場合は、deleteステートメントまたは
/* + TDDL:CMD_EXTRA(TRUNCATE_TABLE_WITH_GSI=TRUE)*/
ヒントを使用します。 - RENAME TABLEまたはALTER TABLE RENAMEステートメントを使用して、グローバルセカンダリインデックスの名前を変更することはできません。 グローバルセカンダリインデックスの名前を変更すると、グローバルセカンダリインデックスのパフォーマンスがマイナスの影響を受ける可能性があります。 グローバルセカンダリインデックスの名前を変更する場合は、DROP indexステートメントを使用してグローバルセカンダリインデックスを削除し、新しいグローバルセカンダリインデックスを作成します。
- ベーステーブルとベーステーブルのインデックステーブル間でデータの一貫性を確保するために、ベーステーブルまたはインデックステーブルでTRUNCATE table文を使用することはできません。 ベーステーブルおよびベーステーブルのインデックステーブルからデータを削除する場合は、deleteステートメントまたは
- グローバルセカンダリインデックスを含むテーブルに対してDMLステートメントを実行する前に、次の制限に注意する必要があります。
- インデックステーブルではDML文を実行できません。
- 指定されたインデックスに基づいてテーブルにデータを書き込むために使用されるDMLステートメントの実行に失敗した場合、ベーステーブルで他のDMLステートメントを実行できず、ベーステーブルでトランザクションをコミットできません。
CREATE TAB_order ( 'id' bigint(11) NOT NULL AUTO_INCREMENT、 'order_id' varchar(20) DEFAULT NULL、 'buyer_id 'varchar(20) デフォルトNULL、 'seller_id 'varchar(20) DEFAULT NULL、 'order_snapshot' ロングテキストDEFAULT NULL、 'order_detail' ロングテキストDEFAULT NULL、 主要なキー ('id') 、 ユニークなキー 'l_i_order ' ('order_id') 、 グローバルインデックス 'g_i_seller ' ('seller_id') dbpartition by hash('seller_id') tbpartition by hash('seller_id') 、 グローバルユニークなインデックス 'g_i_buyer ' ('buyer_id') カバー (order_snapshot) dbpartition by hash('buyer_id') ) ENGINE=InnoDB DEFAULT CHARSET=ハッシュによるutf8 dbpartition ('order_id'); SET DRDS_TRANSACTION_POLICY='XA'; INSERT INTO t_order(order_id, buyer_id, seller_id) 値 ('order_1 ', 'buyer_1', 'seller_1 '); # このDML文の実行が失敗します。 INSERT IGNORE INTO t_order(order_id, buyer_id, seller_id) 値 ('order_2 ', 'buyer_1', 'seller_1 '); # DML文は実行できません。 INSERT IGNORE INTO t_order(order_id, buyer_id, seller_id) 値 ('order_2 ', 'buyer_2', 'seller_2 '); # トランザクションはコミットできません。 コミット;
グローバルセカンダリインデックスの作成
PolarDB-XはMySQL DDL構文をサポートし、グローバルセカンダリインデックスの定義に使用できる構文を提供します。 構文の使用法は、MySQLでインデックスを作成するために使用される構文の使用法と同じです。
- テーブルの作成時にグローバルなセカンダリインデックスを定義する
- テーブルのグローバルセカンダリインデックスの追加
- インデックス名: インデックスの名前。
- インデックスキー列: インデックスが作成される列。 これらの列の名前は、インデックステーブルのシャードキーとして使用されます。 インデックスシャーディングルールを指定する句でシャードキーを指定する必要があります。
- 対象となる列: インデックステーブル内のインデックス列ではない列。 デフォルトでは、基本テーブルの主キーの列とすべてのシャードキーがカバー列として使用されます。
- シャーディング句: インデックス作成ステートメントのシャーディング句は、インデックステーブルのシャーディングアルゴリズムを指定します。 シャーディング句の構文は、CREATE TABLEステートメントで使用される構文と同じです。
- 上記の例では、DRDSモードを使用してパーティション分割されたテーブルのグローバルセカンダリインデックスを作成するために使用される構文について説明しています。 自動パーティショニングモードを使用してパーティション分割されたテーブルのグローバルセカンダリインデックスを作成するために使用される構文については、「create INDEX ( DRDSモード) 」をご参照ください。
例:
# テーブルを作成するときにグローバルセカンダリインデックスを定義する
CREATE TAB_order (
'id' bigint(11) NOT NULL AUTO_INCREMENT、
'order_id' varchar(20) DEFAULT NULL、
'buyer_id 'varchar(20) デフォルトNULL、
'seller_id 'varchar(20) DEFAULT NULL、
'order_snapshot' ロングテキストDEFAULT NULL、
'order_detail' ロングテキストDEFAULT NULL、
主要なキー ('id') 、
グローバルインデックス 'g_i_seller '('seller_id') カバー ('id' 、'order_id' 、'buyer_id' 、'order_snapshot') dbpartition by hash('seller_id')
) ENGINE=InnoDB DEFAULT CHARSET=ハッシュによるutf8 dbpartition ('order_id');
# グローバルセカンダリインデックスの追加
ユニークなグローバルインデックスを作成 'g_i_buyer 'ON 't_order'('buyer_id')
カバー ('seller_id' 、'order_snapshot ')
tbpartition by hash('buyer_id') tbpartition by hash('buyer_id') tbpartitions 3
グローバルセカンダリインデックスの使用
グローバルセカンダリインデックスを作成したら、次のいずれかの方法を使用して、クエリのインデックスを指定します。
- ヒントを使用してインデックスを指定する次のいずれかのヒントを使用して、クエリに使用するインデックスを指定できます。
の例:FORCE INDEX({index_name})
SELECT a.*, b.order_id FROM t_seller a JOIN t_order b FORCE INDEX(g_i_seller) ON a.seller_id = b.seller_id WHERE a.seller_nick="abc";
例:/* + TDDL:INDEX({table_name/table_alias}, {index_name})*/
/* + TDDL:index(a, g_i_buyer)*/ SELECT * FROM t_order a WHERE a.buyer_id = 123
説明 クエリでインデックスに含まれていない列が必要な場合は、最初にインデックステーブルをクエリして、記録されたすべてのプライマリキーとベーステーブルのシャードキーを取得できます。 次に、ベーステーブルを照会して、不足している列の値を取得します。 詳細については、「インデックスヒントの使用方法」をご参照ください。 - インデックステーブルからのデータの照会
テーブルのインデックスにクエリで要求されたすべての列が含まれている場合、結果データはインデックステーブルから取得できます。
- インデックスの選択
グローバルセカンダリインデックスを含むベーステーブルをクエリするには、PolarDB-Xオプティマイザーは、最小限のオーバーヘッドを必要とするインデックステーブルを自動的に選択します。 オプティマイザは、カバーインデックスからのみインデックスを選択できます。 次のSQL文では、実表名がt_orderであり、seller_id列の値が条件として指定されています。 id、order_snapshot、およびseller_id列は、g_i_sellerグローバルセカンダリインデックスでカバーされます。 g_i_sellerグローバルセカンダリインデックスはカバーインデックスであり、seller_idはg_i_sellerインデックステーブルのシャードキーです。 このグローバルセカンダリインデックスを使用してデータをクエリすると、PolarDB-Xはカバー列からデータをクエリできます。 この場合、スキャンされるシャードの数が減少します。 EXPLAINステートメントの結果は、PolarDB-Xオプティマイザがg_i_sellerインデックステーブルを選択することを示しています。
EXPLAIN SELECT t_order.id,t_order.order_snapshot FROM t_order WHERE t_order.seller_id = 's1'; IndexScan(tables="g_i_seller_sfL1_2" 、sql="SELECT 'id' 、'order_snapshot' FROM 'g_i_seller 'AS 'g_i_seller' WHERE ('seller_id' = ?)")
- IGNORE INDEXまたはUse INDEXステートメントを使用する次のヒントを使用して、オプティマイザで使用でき、オプティマイザで使用できないインデックスを指定できます。
例:IGNORE INDEX({index_name},...)
SELECT t_order.id,t_order.order_snapshot FROM t_order IGNORE INDEX(g_i_seller) WHERE t_order.seller_id = 's1';
例:インデックスを使用 ({index_name},...)
SELECT t_order.id,t_order.order_snapshot FROM t_order USE INDEX(g_i_seller) WHERE t_order.seller_id = 's1';