- TiDBについて
- クイックスタート
- 発展させる
- 概要
- クイックスタート
- TiDB CloudでTiDBクラスターを構築する(DevTier)
- TiDBのCRUDSQL
- TiDBを使用してシンプルなCRUDアプリを構築する
- アプリケーション例
- TiDBに接続する
- データベーススキーマの設計
- データの書き込み
- データの読み取り
- 取引
- 最適化
- トラブルシューティング
- 参照
- デプロイ
- 移行する
- 管理
- 監視と警告
- トラブルシューティング
- TiDBトラブルシューティングマップ
- 遅いクエリを特定する
- 遅いクエリを分析する
- SQL診断
- Top SQLを使用して高価なクエリを特定する
- ログを使用して高価なクエリを特定する
- ステートメント要約表
- ホットスポットの問題のトラブルシューティング
- 読み取りと書き込みの待ち時間の増加のトラブルシューティング
- クラスタのオンサイト情報を保存および復元する
- クラスタセットアップのトラブルシューティング
- 高いディスクI/O使用量のトラブルシューティング
- ロックの競合のトラブルシューティング
- TiFlashのトラブルシューティング
- 楽観的なトランザクションでの書き込みの競合のトラブルシューティング
- データとインデックス間の不整合のトラブルシューティング
- 性能チューニング
- チューニングガイド
- Configuration / コンフィグレーションの調整
- システムチューニング
- ソフトウェアのチューニング
- SQLチューニング
- チュートリアル
- TiDBツール
- 概要
- ユースケース
- ダウンロード
- TiUP
- ドキュメントマップ
- 概要
- 用語と概念
- TiUPコンポーネントを管理する
- FAQ
- トラブルシューティングガイド
- コマンドリファレンス
- 概要
- TiUPコマンド
- TiUPクラスターコマンド
- 概要
- tiup cluster audit
- tiup cluster check
- tiup cluster clean
- tiup cluster deploy
- tiup cluster destroy
- tiup cluster disable
- tiup cluster display
- tiup cluster edit-config
- tiup cluster enable
- tiup cluster help
- tiup cluster import
- tiup cluster list
- tiup cluster patch
- tiup cluster prune
- tiup cluster reload
- tiup cluster rename
- tiup cluster replay
- tiup cluster restart
- tiup cluster scale-in
- tiup cluster scale-out
- tiup cluster start
- tiup cluster stop
- tiup cluster template
- tiup cluster upgrade
- TiUPDMコマンド
- 概要
- tiup dm audit
- tiup dm deploy
- tiup dm destroy
- tiup dm disable
- tiup dm display
- tiup dm edit-config
- tiup dm enable
- tiup dm help
- tiup dm import
- tiup dm list
- tiup dm patch
- tiup dm prune
- tiup dm reload
- tiup dm replay
- tiup dm restart
- tiup dm scale-in
- tiup dm scale-out
- tiup dm start
- tiup dm stop
- tiup dm template
- tiup dm upgrade
- TiDBクラスタートポロジリファレンス
- DMクラスタートポロジリファレンス
- ミラーリファレンスガイド
- TiUPコンポーネント
- PingCAPクリニック診断サービス(テクニカルプレビュー)
- TiDB Operator
- Dumpling
- TiDB Lightning
- TiDBデータ移行
- TiDBデータ移行について
- クイックスタート
- DMクラスタをデプロイする
- チュートリアル
- 高度なチュートリアル
- シャーディングされたテーブルからのデータのマージと移行
- GH-ost/PT-oscを使用するMySQLデータベースからの移行
- より多くの列を持つダウンストリームTiDBテーブルにデータを移行する
- 管理
- 参照
- 例
- トラブルシューティング
- リリースノート
- バックアップと復元(BR)
- TiDB Binlog
- TiCDC
- Dumpling
- sync-diff-inspector
- TiSpark
- 参照
- クラスターアーキテクチャ
- 主要な監視指標
- セキュリティ
- 権限
- SQL
- SQL言語の構造と構文
- SQLステートメント
ADD COLUMN
ADD INDEX
ADMIN
ADMIN CANCEL DDL
ADMIN CHECKSUM TABLE
ADMIN CHECK [TABLE|INDEX]
ADMIN SHOW DDL [JOBS|QUERIES]
ADMIN SHOW TELEMETRY
ALTER DATABASE
ALTER INDEX
ALTER INSTANCE
ALTER PLACEMENT POLICY
ALTER TABLE
ALTER USER
ANALYZE TABLE
BACKUP
BATCH
BEGIN
CHANGE COLUMN
COMMIT
CHANGE DRAINER
CHANGE PUMP
CREATE [GLOBAL|SESSION] BINDING
CREATE DATABASE
CREATE INDEX
CREATE PLACEMENT POLICY
CREATE ROLE
CREATE SEQUENCE
CREATE TABLE LIKE
CREATE TABLE
CREATE USER
CREATE VIEW
DEALLOCATE
DELETE
DESC
DESCRIBE
DO
DROP [GLOBAL|SESSION] BINDING
DROP COLUMN
DROP DATABASE
DROP INDEX
DROP PLACEMENT POLICY
DROP ROLE
DROP SEQUENCE
DROP STATS
DROP TABLE
DROP USER
DROP VIEW
EXECUTE
EXPLAIN ANALYZE
EXPLAIN
FLASHBACK TABLE
FLUSH PRIVILEGES
FLUSH STATUS
FLUSH TABLES
GRANT <privileges>
GRANT <role>
INSERT
KILL [TIDB]
LOAD DATA
LOAD STATS
MODIFY COLUMN
PREPARE
RECOVER TABLE
RENAME INDEX
RENAME TABLE
REPLACE
RESTORE
REVOKE <privileges>
REVOKE <role>
ROLLBACK
SELECT
SET DEFAULT ROLE
SET [NAMES|CHARACTER SET]
SET PASSWORD
SET ROLE
SET TRANSACTION
SET [GLOBAL|SESSION] <variable>
SHOW ANALYZE STATUS
SHOW [BACKUPS|RESTORES]
SHOW [GLOBAL|SESSION] BINDINGS
SHOW BUILTINS
SHOW CHARACTER SET
SHOW COLLATION
SHOW [FULL] COLUMNS FROM
SHOW CONFIG
SHOW CREATE PLACEMENT POLICY
SHOW CREATE SEQUENCE
SHOW CREATE TABLE
SHOW CREATE USER
SHOW DATABASES
SHOW DRAINER STATUS
SHOW ENGINES
SHOW ERRORS
SHOW [FULL] FIELDS FROM
SHOW GRANTS
SHOW INDEX [FROM|IN]
SHOW INDEXES [FROM|IN]
SHOW KEYS [FROM|IN]
SHOW MASTER STATUS
SHOW PLACEMENT
SHOW PLACEMENT FOR
SHOW PLACEMENT LABELS
SHOW PLUGINS
SHOW PRIVILEGES
SHOW [FULL] PROCESSSLIST
SHOW PROFILES
SHOW PUMP STATUS
SHOW SCHEMAS
SHOW STATS_HEALTHY
SHOW STATS_HISTOGRAMS
SHOW STATS_META
SHOW STATUS
SHOW TABLE NEXT_ROW_ID
SHOW TABLE REGIONS
SHOW TABLE STATUS
SHOW [FULL] TABLES
SHOW [GLOBAL|SESSION] VARIABLES
SHOW WARNINGS
SHUTDOWN
SPLIT REGION
START TRANSACTION
TABLE
TRACE
TRUNCATE
UPDATE
USE
WITH
- データ型
- 関数と演算子
- クラスター化インデックス
- 制約
- 生成された列
- SQLモード
- テーブル属性
- トランザクション
- ガベージコレクション(GC)
- ビュー
- パーティショニング
- 一時テーブル
- キャッシュされたテーブル
- 文字セットと照合
- SQLの配置ルール
- システムテーブル
mysql
- INFORMATION_SCHEMA
- 概要
ANALYZE_STATUS
CLIENT_ERRORS_SUMMARY_BY_HOST
CLIENT_ERRORS_SUMMARY_BY_USER
CLIENT_ERRORS_SUMMARY_GLOBAL
CHARACTER_SETS
CLUSTER_CONFIG
CLUSTER_HARDWARE
CLUSTER_INFO
CLUSTER_LOAD
CLUSTER_LOG
CLUSTER_SYSTEMINFO
COLLATIONS
COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
DATA_LOCK_WAITS
DDL_JOBS
DEADLOCKS
ENGINES
INSPECTION_RESULT
INSPECTION_RULES
INSPECTION_SUMMARY
KEY_COLUMN_USAGE
METRICS_SUMMARY
METRICS_TABLES
PARTITIONS
PLACEMENT_POLICIES
PROCESSLIST
REFERENTIAL_CONSTRAINTS
SCHEMATA
SEQUENCES
SESSION_VARIABLES
SLOW_QUERY
STATISTICS
TABLES
TABLE_CONSTRAINTS
TABLE_STORAGE_STATS
TIDB_HOT_REGIONS
TIDB_HOT_REGIONS_HISTORY
TIDB_INDEXES
TIDB_SERVERS_INFO
TIDB_TRX
TIFLASH_REPLICA
TIKV_REGION_PEERS
TIKV_REGION_STATUS
TIKV_STORE_STATUS
USER_PRIVILEGES
VIEWS
METRICS_SCHEMA
- UI
- TiDBダッシュボード
- 概要
- 管理
- アクセス
- 概要ページ
- クラスター情報ページ
- Top SQLページ
- キービジュアライザーページ
- メトリクス関係グラフ
- SQLステートメント分析
- 遅いクエリページ
- クラスター診断
- 検索ログページ
- インスタンスプロファイリング
- セッションの管理とConfiguration / コンフィグレーション
- FAQ
- CLI
- コマンドラインフラグ
- Configuration / コンフィグレーションファイルのパラメーター
- システム変数
- ストレージエンジン
- テレメトリー
- エラーコード
- テーブルフィルター
- トポロジラベルによるレプリカのスケジュール
- よくある質問
- リリースノート
- すべてのリリース
- リリースタイムライン
- TiDBバージョニング
- v6.1
- v6.0
- v5.4
- v5.3
- v5.2
- v5.1
- v5.0
- v4.0
- v3.1
- v3.0
- v2.1
- v2.0
- v1.0
- 用語集
インデックスの選択
ストレージエンジンからのデータの読み取りは、SQL実行中に最も時間のかかる手順の1つです。現在、TiDBは、さまざまなストレージエンジンおよびさまざまなインデックスからのデータの読み取りをサポートしています。クエリ実行のパフォーマンスは、適切なインデックスを選択するかどうかに大きく依存します。
このドキュメントでは、テーブルにアクセスするためのインデックスを選択する方法と、インデックスの選択を制御するためのいくつかの関連する方法を紹介します。
テーブルにアクセスする
インデックスの選択を導入する前に、TiDBがテーブルにアクセスする方法、各方法でトリガーされるもの、各方法でどのような違いが生じるか、および長所と短所を理解することが重要です。
テーブルにアクセスするための演算子
オペレーター | トリガー条件 | 該当するシナリオ | 説明 |
---|---|---|---|
PointGet / BatchPointGet | 1つ以上のシングルポイント範囲のテーブルにアクセスする場合。 | 任意のシナリオ | トリガーされた場合、コプロセッサー・インターフェースを呼び出すのではなく、kvgetインターフェースを直接呼び出して計算を実行するため、通常は最速のオペレーターと見なされます。 |
TableReader | なし | 任意のシナリオ | これは一般に、TiKVレイヤーから直接テーブルデータをスキャンする最も効率の悪いオペレーターと見なされています。 _tidb_rowid 列に範囲クエリがある場合、またはテーブルにアクセスして選択する他の演算子がない場合にのみ選択できます。 |
TableReader | テーブルには、TiFlashノードにレプリカがあります。 | 読み取る列は少なくなりますが、評価する行は多くなります。 | Tiflashは列ベースのストレージです。少数の列と多数の行を計算する必要がある場合は、この演算子を選択することをお勧めします。 |
IndexReader | テーブルには1つ以上のインデックスがあり、計算に必要な列がインデックスに含まれています。 | インデックスに狭い範囲のクエリがある場合、またはインデックス付き列の順序要件がある場合。 | 複数のインデックスが存在する場合、コスト見積もりに基づいて適切なインデックスが選択されます。 |
IndexLookupReader | テーブルには1つ以上のインデックスがあり、計算に必要な列がインデックスに完全に含まれているわけではありません。 | IndexReaderと同じです。 | インデックスは計算列を完全にはカバーしていないため、TiDBはインデックスを読み取った後にテーブルから行を取得する必要があります。 IndexReaderオペレーターと比較して追加コストがかかります。 |
ノート:
TableReader演算子は
_tidb_rowid
列のインデックスに基づいており、TiFlashは列ストレージインデックスを使用するため、インデックスの選択はテーブルにアクセスするための演算子の選択です。
インデックス選択ルール
TiDBは、ルールまたはコストに基づいてインデックスを選択します。ベースのルールには、事前ルールとスカイライン剪定が含まれます。インデックスを選択するとき、TiDBは最初にプレルールを試行します。インデックスが事前ルールを満たしている場合、TiDBはこのインデックスを直接選択します。それ以外の場合、TiDBはスカイラインプルーニングを使用して不適切なインデックスを除外し、テーブルにアクセスする各オペレーターのコスト見積もりに基づいて、コストが最も低いインデックスを選択します。
ルールベースの選択
事前ルール
TiDBは、次のヒューリスティックな事前ルールを使用してインデックスを選択します。
ルール1:インデックスが「完全一致の一意のインデックス+テーブルから行を取得する必要がない(つまり、インデックスによって生成されるプランがIndexReader演算子である)」を満たす場合、TiDBはこのインデックスを直接選択します。
ルール2:インデックスが「完全一致の一意のインデックス+テーブルから行を取得する必要がある(つまり、インデックスによって生成されるプランがIndexReader演算子である)」を満たす場合、TiDBは行数が最も少ないインデックスを選択します。候補インデックスとしてテーブルから取得されます。
ルール3:インデックスが「通常のインデックス+テーブルから行を取得する必要がない+読み取る行数が特定のしきい値の値より少ない」を満たす場合、TiDBは行数が最も少ないインデックスを選択します。候補インデックスとして読み取ります。
ルール4:ルール2および3に基づいて候補インデックスが1つだけ選択されている場合は、この候補インデックスを選択します。ルール2と3に基づいてそれぞれ2つの候補インデックスを選択する場合は、読み取る行数が少ないインデックスを選択します(インデックスを持つ行の数+テーブルから取得する行の数)。
上記のルールの「完全一致のインデックス」は、インデックスが付けられた各列の条件が等しいことを意味します。 EXPLAIN FORMAT = 'verbose' ...
ステートメントを実行するときに、事前ルールがインデックスと一致する場合、TiDBは、インデックスが事前ルールと一致することを示すNOTEレベルの警告を出力します。
次の例では、インデックスidx_b
がルール2の「完全一致の一意のインデックス+テーブルから行を取得する必要がある」という条件を満たしているため、TiDBはインデックスidx_b
をアクセスパスとして選択し、 SHOW WARNING
は次のことを示すメモを返します。インデックスidx_b
は事前ルールと一致します。
mysql> CREATE TABLE t(a INT PRIMARY KEY, b INT, c INT, UNIQUE INDEX idx_b(b));
Query OK, 0 rows affected (0.01 sec)
mysql> EXPLAIN FORMAT = 'verbose' SELECT b, c FROM t WHERE b = 3 OR b = 6;
+-------------------+---------+---------+------+-------------------------+------------------------------+
| id | estRows | estCost | task | access object | operator info |
+-------------------+---------+---------+------+-------------------------+------------------------------+
| Batch_Point_Get_5 | 2.00 | 8.80 | root | table:t, index:idx_b(b) | keep order:false, desc:false |
+-------------------+---------+---------+------+-------------------------+------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+-------+------+-------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+-------------------------------------------------------------------------------------------+
| Note | 1105 | unique index idx_b of t is selected since the path only has point ranges with double scan |
+-------+------+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
スカイライン剪定
スカイラインプルーニングは、インデックスのヒューリスティックフィルタリングルールであり、誤った推定によって誤ったインデックスが選択される可能性を減らすことができます。インデックスを判断するには、次の3つの次元が必要です。
インデックス付きの列でカバーされるアクセス条件の数。 「アクセス条件」は、列範囲に変換できるwhere条件です。また、インデックス付きの列セットがカバーするアクセス条件が多ければ多いほど、この次元でのパフォーマンスは向上します。
テーブルにアクセスするためにインデックスを選択するときにテーブルから行を取得する必要があるかどうか(つまり、インデックスによって生成されるプランはIndexReader演算子またはIndexLookupReader演算子です)。テーブルから行を取得しないインデックスは、取得するインデックスよりもこのディメンションに適しています。両方のインデックスでテーブルから行を取得するためにTiDBが必要な場合は、インデックス付きの列でカバーされるフィルタリング条件の数を比較します。フィルタリング条件とは、インデックスに基づいて判断できる
where
の条件を意味します。インデックスの列セットがより多くのアクセス条件をカバーする場合、テーブルから取得される行の数が少なくなり、このディメンションでのインデックスの品質が向上します。インデックスが特定の順序を満たすかどうかを選択します。インデックスの読み取りは特定の列セットの順序を保証できるため、クエリの順序を満たすインデックスは、このディメンションで満たさないインデックスよりも優れています。
上記のこれらの3つの次元では、インデックスidx_a
が3つの次元すべてでインデックスidx_b
よりも悪くなく、1つの次元でidx_b
よりも優れている場合は、 idx_a
が優先されます。 EXPLAIN FORMAT = 'verbose' ...
ステートメントを実行するときに、skyline-pruningが一部のインデックスを除外すると、TiDBは、skyline-pruning除外後の残りのインデックスをリストするNOTEレベルの警告を出力します。
次の例では、インデックスidx_b
とidx_e
はどちらもidx_b_c
より劣っているため、スカイラインプルーニングによって除外されます。返される結果SHOW WARNING
は、スカイラインプルーニング後の残りのインデックスを表示します。
mysql> CREATE TABLE t(a INT PRIMARY KEY, b INT, c INT, d INT, e INT, INDEX idx_b(b), INDEX idx_b_c(b, c), INDEX idx_e(e));
Query OK, 0 rows affected (0.01 sec)
mysql> EXPLAIN FORMAT = 'verbose' SELECT * FROM t WHERE b = 2 AND c > 4;
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
| id | estRows | estCost | task | access object | operator info |
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
| IndexLookUp_10 | 33.33 | 738.29 | root | | |
| ├─IndexRangeScan_8(Build) | 33.33 | 2370.00 | cop[tikv] | table:t, index:idx_b_c(b, c) | range:(2 4,2 +inf], keep order:false, stats:pseudo |
| └─TableRowIDScan_9(Probe) | 33.33 | 2370.00 | cop[tikv] | table:t | keep order:false, stats:pseudo |
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
3 rows in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+-------+------+------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------------------------+
| Note | 1105 | [t,idx_b_c] remain after pruning paths for t given Prop{SortItems: [], TaskTp: rootTask} |
+-------+------+------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
コスト見積もりベースの選択
スカイラインプルーニングルールを使用して不適切なインデックスを除外した後、インデックスの選択は完全にコスト見積もりに基づいています。テーブルへのアクセスのコスト見積もりには、次の考慮事項が必要です。
- ストレージエンジンのインデックス付きデータの各行の平均の長さ。
- インデックスによって生成されたクエリ範囲の行数。
- テーブルから行を取得するためのコスト。
- クエリの実行中にインデックスによって生成された範囲の数。
これらの要因とコストモデルに従って、オプティマイザはテーブルにアクセスするためのコストが最も低いインデックスを選択します。
コスト見積もりベースの選択に関する一般的なチューニングの問題
推定行数は正確ではありませんか?
これは通常、古い統計または不正確な統計が原因です。
analyze table
ステートメントを再実行するか、analyze table
ステートメントのパラメーターを変更できます。統計は正確で、TiFlashからの読み取りは高速ですが、オプティマイザーがTiKVからの読み取りを選択するのはなぜですか?
現在、TiFlashとTiKVを区別するためのコストモデルはまだ大まかなものです。
tidb_opt_seek_factor
つのパラメーターの値を減らすことができ、オプティマイザーはTiFlashを選択することを選択します。統計は正確です。インデックスAはテーブルから行を取得する必要がありますが、実際には、テーブルから行を取得しないインデックスBよりも高速に実行されます。オプティマイザがインデックスBを選択するのはなぜですか?
この場合、コスト見積もりはテーブルから行を取得するには大きすぎる可能性があります。
tidb_opt_network_factor
パラメーターの値を減らして、テーブルから行を取得するコストを減らすことができます。
コントロールインデックスの選択
インデックスの選択は、 オプティマイザーのヒントを介した単一のクエリで制御できます。
USE_INDEX
は、オプティマイザに特定のインデックスを使用するIGNORE_INDEX
使用しないように強制することができます。FORCE_INDEX
とUSE_INDEX
は同じ効果があります。READ_FROM_STORAGE
を指定すると、オプティマイザは、クエリを実行するために特定のテーブルに対してTiKV/TiFlashストレージエンジンを選択するように強制できます。