クラスタ化インデックス
TiDB は v5.0 以降、クラスター化インデックス機能をサポートしています。この機能は、主キーを含むテーブルにデータを格納する方法を制御します。特定のクエリのパフォーマンスを向上させる方法でテーブルを編成する機能を TiDB に提供します。
このコンテキストでのクラスタ化という用語は、データの格納方法の編成を指し、連携して動作するデータベース サーバーのグループを指すわけではありません。一部のデータベース管理システムでは、クラスター化インデックスをインデックス構成テーブル(IOT) と呼んでいます。
現在、TiDB の主キーを含むテーブルは、次の 2 つのカテゴリに分類されます。
NONCLUSTERED
: テーブルの主キーは非クラスター化インデックスです。非クラスター化インデックスを持つテーブルでは、行データのキーは、TiDB によって暗黙的に割り当てられた内部_tidb_rowid
で構成されます。主キーは基本的に一意のインデックスであるため、非クラスター化インデックスを含むテーブルには、行を格納するために少なくとも 2 つのキーと値のペアが必要です。_tidb_rowid
(キー) - 行データ (値)- 主キー データ (キー) -
_tidb_rowid
(値)
CLUSTERED
: テーブルの主キーはクラスター化インデックスです。クラスタ化インデックスを持つテーブルでは、行データのキーは、ユーザーが指定した主キー データで構成されます。したがって、クラスター化されたインデックスを持つテーブルでは、行を格納するために必要なキーと値のペアは 1 つだけです。- 主キーデータ(キー) - 行データ(値)
ノート:
TiDB は、テーブルの
PRIMARY KEY
によるクラスタリングのみをサポートします。クラスター化インデックスを有効にすると、PRIMARY KEY
とクラスター化インデックスという用語が同じ意味で使用される場合があります。PRIMARY KEY
は制約 (論理プロパティ) を参照し、クラスター化インデックスはデータの格納方法の物理的な実装を記述します。
ユーザー シナリオ
クラスター化されていないインデックスを含むテーブルと比較して、クラスター化されたインデックスを含むテーブルは、次のシナリオでより優れたパフォーマンスとスループットの利点を提供します。
- データが挿入されると、クラスター化インデックスは、ネットワークからのインデックス データの 1 回の書き込みを減らします。
- 同等の条件を持つクエリに主キーのみが含まれる場合、クラスター化インデックスは、ネットワークからのインデックス データの 1 回の読み取りを減らします。
- 範囲条件を含むクエリに主キーのみが含まれる場合、クラスター化インデックスにより、ネットワークからのインデックス データの複数回の読み取りが削減されます。
- 同等または範囲条件を含むクエリに主キー プレフィックスのみが含まれる場合、クラスター化インデックスは、ネットワークからのインデックス データの複数回の読み取りを減らします。
一方、クラスター化されたインデックスを持つテーブルには、特定の欠点があります。以下を参照してください。
- 近い値を持つ多数の主キーを挿入すると、書き込みホットスポットの問題が発生する可能性があります。
- 主キーのデータ型が 64 ビットより大きい場合、特に複数のセカンダリ インデックスがある場合、テーブル データはより多くのストレージ領域を占有します。
用途
クラスター化インデックスを含むテーブルを作成する
TiDB v5.0 以降、 CREATE TABLE
ステートメントのPRIMARY KEY
の後に予約されていないキーワードCLUSTERED
またはNONCLUSTERED
を追加して、テーブルの主キーがクラスター化インデックスであるかどうかを指定できます。例えば:
CREATE TABLE t (a BIGINT PRIMARY KEY CLUSTERED, b VARCHAR(255));
CREATE TABLE t (a BIGINT PRIMARY KEY NONCLUSTERED, b VARCHAR(255));
CREATE TABLE t (a BIGINT KEY CLUSTERED, b VARCHAR(255));
CREATE TABLE t (a BIGINT KEY NONCLUSTERED, b VARCHAR(255));
CREATE TABLE t (a BIGINT, b VARCHAR(255), PRIMARY KEY(a, b) CLUSTERED);
CREATE TABLE t (a BIGINT, b VARCHAR(255), PRIMARY KEY(a, b) NONCLUSTERED);
キーワードKEY
とPRIMARY KEY
は、列定義で同じ意味を持つことに注意してください。
TiDB のコメント構文を使用して、主キーのタイプを指定することもできます。例えば:
CREATE TABLE t (a BIGINT PRIMARY KEY /*T![clustered_index] CLUSTERED */, b VARCHAR(255));
CREATE TABLE t (a BIGINT PRIMARY KEY /*T![clustered_index] NONCLUSTERED */, b VARCHAR(255));
CREATE TABLE t (a BIGINT, b VARCHAR(255), PRIMARY KEY(a, b) /*T![clustered_index] CLUSTERED */);
CREATE TABLE t (a BIGINT, b VARCHAR(255), PRIMARY KEY(a, b) /*T![clustered_index] NONCLUSTERED */);
キーワードCLUSTERED
を明示的に指定しないステートメントの場合、デフォルトの動作はシステム変数NONCLUSTERED
によって制御され@@global.tidb_enable_clustered_index
。この変数でサポートされている値は次のとおりです。
OFF
は、主キーが既定で非クラスター化インデックスとして作成されることを示します。ON
は、主キーが既定でクラスター化インデックスとして作成されることを示します。INT_ONLY
は、動作が構成アイテムalter-primary-key
によって制御されることを示します。alter-primary-key
がtrue
に設定されている場合、主キーはデフォルトで非クラスター化インデックスとして作成されます。false
に設定すると、整数列で構成される主キーのみがクラスター化インデックスとして作成されます。
@@global.tidb_enable_clustered_index
のデフォルト値はINT_ONLY
です。
クラスター化インデックスを追加または削除する
TiDB は、テーブル作成後のクラスタ化インデックスの追加または削除をサポートしていません。また、クラスター化インデックスと非クラスター化インデックス間の相互変換もサポートしていません。例えば:
ALTER TABLE t ADD PRIMARY KEY(b, a) CLUSTERED; -- Currently not supported.
ALTER TABLE t DROP PRIMARY KEY; -- If the primary key is a clustered index, then not supported.
ALTER TABLE t DROP INDEX `PRIMARY`; -- If the primary key is a clustered index, then not supported.
非クラスター化インデックスを追加または削除する
TiDB は、テーブル作成後の非クラスター化インデックスの追加または削除をサポートしています。キーワードNONCLUSTERED
を明示的に指定することも、省略することもできます。例えば:
ALTER TABLE t ADD PRIMARY KEY(b, a) NONCLUSTERED;
ALTER TABLE t ADD PRIMARY KEY(b, a); -- If you omit the keyword, the primary key is a non-clustered index by default.
ALTER TABLE t DROP PRIMARY KEY;
ALTER TABLE t DROP INDEX `PRIMARY`;
主キーがクラスター化インデックスかどうかを確認する
次のいずれかの方法を使用して、テーブルの主キーがクラスター化インデックスであるかどうかを確認できます。
- コマンド
SHOW CREATE TABLE
を実行します。 - コマンド
SHOW INDEX FROM
を実行します。 - システム テーブル
information_schema.tables
のTIDB_PK_TYPE
列をクエリします。
コマンドSHOW CREATE TABLE
を実行すると、 PRIMARY KEY
の属性がCLUSTERED
かNONCLUSTERED
ます。例えば:
mysql> SHOW CREATE TABLE t;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t | CREATE TABLE `t` (
`a` bigint(20) NOT NULL,
`b` varchar(255) DEFAULT NULL,
PRIMARY KEY (`a`) /*T![clustered_index] CLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
コマンドSHOW INDEX FROM
を実行すると、列Clustered
の結果がYES
かNO
かを確認できます。例えば:
mysql> SHOW INDEX FROM t;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+-----------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | Clustered |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+-----------+
| t | 0 | PRIMARY | 1 | a | A | 0 | NULL | NULL | | BTREE | | | YES | NULL | YES |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+-----------+
1 row in set (0.01 sec)
システム テーブルinformation_schema.tables
の列TIDB_PK_TYPE
をクエリして、結果がCLUSTERED
かNONCLUSTERED
かを確認することもできます。例えば:
mysql> SELECT TIDB_PK_TYPE FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't';
+--------------+
| TIDB_PK_TYPE |
+--------------+
| CLUSTERED |
+--------------+
1 row in set (0.03 sec)
制限事項
現在、クラスター化インデックス機能にはいくつかの異なる種類の制限があります。以下を参照してください。
- サポートされておらず、サポート プランにも含まれていない状況:
- クラスター化インデックスを属性
SHARD_ROW_ID_BITS
と一緒に使用することはサポートされていません。また、属性PRE_SPLIT_REGIONS
は、クラスター化インデックスを持つテーブルでは有効になりません。 - クラスター化インデックスを含むテーブルのダウングレードはサポートされていません。そのようなテーブルをダウングレードする必要がある場合は、代わりに論理バックアップ ツールを使用してデータを移行してください。
- クラスター化インデックスを属性
- まだサポートされていないが、サポート プランに含まれる状況:
ALTER TABLE
ステートメントを使用したクラスター化インデックスの追加、削除、および変更はサポートされていません。
- 特定のバージョンの制限:
- v5.0 では、クラスター化インデックス機能を TiDB Binlogと一緒に使用することはサポートされていません。 TiDB Binlogが有効になった後、TiDB は主キーのクラスター化インデックスとして単一の整数列の作成のみを許可します。 TiDB Binlogは、クラスター化されたインデックスを持つ既存のテーブルのデータ変更 (挿入、削除、更新など) をダウンストリームに複製しません。クラスター化されたインデックスを含むテーブルをダウンストリームにレプリケートする必要がある場合は、クラスターを v5.1 にアップグレードするか、代わりにレプリケーションにTiCDCを使用してください。
TiDB Binlogを有効にした後、作成したクラスター化インデックスが単一の整数の主キーでない場合、TiDB は次のエラーを返します。
mysql> CREATE TABLE t (a VARCHAR(255) PRIMARY KEY CLUSTERED);
ERROR 8200 (HY000): Cannot create clustered index table when the binlog is ON
クラスター化インデックスを属性SHARD_ROW_ID_BITS
と一緒に使用すると、TiDB は次のエラーを報告します。
mysql> CREATE TABLE t (a VARCHAR(255) PRIMARY KEY CLUSTERED) SHARD_ROW_ID_BITS = 3;
ERROR 8200 (HY000): Unsupported shard_row_id_bits for table with primary key as row id
互換性
以前および以降の TiDB バージョンとの互換性
TiDB は、クラスター化インデックスを持つテーブルのアップグレードをサポートしますが、そのようなテーブルのダウングレードはサポートしません。つまり、新しい TiDB バージョンのクラスター化インデックスを持つテーブルのデータは、以前のバージョンでは利用できません。
クラスター化インデックス機能は、TiDB v3.0 および v4.0 で部分的にサポートされています。次の要件が完全に満たされると、デフォルトで有効になります。
- テーブルには
PRIMARY KEY
が含まれています。 PRIMARY KEY
は 1 つの列のみで構成されます。PRIMARY KEY
はINTEGER
です。
TiDB v5.0 以降、クラスター化インデックス機能はすべてのタイプの主キーで完全にサポートされていますが、デフォルトの動作は TiDB v3.0 および v4.0 と一致しています。デフォルトの動作を変更するには、システム変数@@tidb_enable_clustered_index
をON
またはOFF
に構成できます。詳細については、 クラスター化インデックスを含むテーブルを作成するを参照してください。
MySQL との互換性
TiDB 固有のコメント構文は、キーワードCLUSTERED
とNONCLUSTERED
をコメントでラップすることをサポートしています。 SHOW CREATE TABLE
の結果には、TiDB 固有の SQL コメントも含まれています。以前のバージョンの MySQL データベースおよび TiDB データベースは、これらのコメントを無視します。
TiDB 移行ツールとの互換性
クラスター化インデックス機能は、v5.0 以降のバージョンの次の移行ツールとのみ互換性があります。
- バックアップおよび復元ツール: BR、 Dumpling、およびTiDB Lightning。
- データ移行および複製ツール: DM および TiCDC。
ただし、v5.0 BR ツールを使用してテーブルをバックアップおよび復元しても、非クラスター化インデックスを含むテーブルをクラスター化インデックスを含むテーブルに変換することはできません。
他の TiDB 機能との互換性
結合された主キーまたは単一の非整数主キーを持つテーブルの場合、主キーを非クラスター化インデックスからクラスター化インデックスに変更すると、その行データのキーも変更されます。したがって、v5.0 より前のバージョンの TiDB で実行可能なSPLIT TABLE BY/BETWEEN
ステートメントは、v5.0 以降のバージョンの TiDB では実行できなくなりました。 SPLIT TABLE BY/BETWEEN
を使用してクラスター化インデックスを持つテーブルを分割する場合は、整数値を指定する代わりに、主キー列の値を指定する必要があります。次の例を参照してください。
mysql> create table t (a int, b varchar(255), primary key(a, b) clustered);
Query OK, 0 rows affected (0.01 sec)
mysql> split table t between (0) and (1000000) regions 5;
ERROR 1105 (HY000): Split table region lower value count should be 2
mysql> split table t by (0), (50000), (100000);
ERROR 1136 (21S01): Column count doesn't match value count at row 0
mysql> split table t between (0, 'aaa') and (1000000, 'zzz') regions 5;
+--------------------+----------------------+
| TOTAL_SPLIT_REGION | SCATTER_FINISH_RATIO |
+--------------------+----------------------+
| 4 | 1 |
+--------------------+----------------------+
1 row in set (0.00 sec)
mysql> split table t by (0, ''), (50000, ''), (100000, '');
+--------------------+----------------------+
| TOTAL_SPLIT_REGION | SCATTER_FINISH_RATIO |
+--------------------+----------------------+
| 3 | 1 |
+--------------------+----------------------+
1 row in set (0.01 sec)
属性AUTO_RANDOM
は、クラスター化インデックスでのみ使用できます。それ以外の場合、TiDB は次のエラーを返します。
mysql> create table t (a bigint primary key nonclustered auto_random);
ERROR 8216 (HY000): Invalid auto random: column a is not the integer primary key, or the primary key is nonclustered