MySQL inndbジョイントインデックスを正しく使用する方法を徹底的に理解するためのケーススタディ

MySQL inndbジョイントインデックスを正しく使用する方法を徹底的に理解するためのケーススタディ

最近確認された5件のデータを照会するビジネスがあります。

`id`、`title` を選択
`th_content` から
ここで、`audit_time` < 1541984478
 かつ `ステータス` = 'オンライン'
`audit_time` DESC、`id` DESC で並べ替え
制限5;

当時の監視状況を確認すると、CPU 使用率が 100% を超えていました。Show show processlist見ると、多くの類似クエリがcreate sort index状態にあることがわかりました。

テーブルの構造を表示する

テーブル `th_content` を作成します (
 `id` bigint(20) 符号なし NOT NULL AUTO_INCREMENT,
 `title` varchar(500) 文字セット utf8 NOT NULL デフォルト '' COMMENT 'コンテンツのタイトル',
 `content` mediumtext CHARACTER SET utf8 NOT NULL COMMENT 'メインコンテンツ',
 `audit_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '監査時間',
 `last_edit_time` タイムスタンプ NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最終編集時間',
 `status` enum('CREATED','CHECKING','IGNORED','ONLINE','OFFLINE') 文字セット utf8 NOT NULL デフォルト 'CREATED' コメント '情報ステータス',
 主キー (`id`)、
 キー `idx_at_let` (`audit_time`,`last_edit_time`)
)ENGINE=InnoDB デフォルト文字セット=utf8mb4;

インデックスには、左側にaudit_timeとの結合インデックスがあり、 statusにはインデックスがありません。

上記の SQL 実行のロジックを分析します。

  • 共同インデックスからレビュー時間未満のすべての主キー ID を検索します (このタイムスタンプより前に 100 万件のデータがレビューされている場合、対応する 100 万件のデータの主キー ID が共同インデックスから取得されます)
  • 将来的に最適化が行われると良いでしょう。現在のところ、100 個の主キー ID をソートし、テーブルを返す操作の次のステップで、互いに近い主キーを 1 回のディスク I/O で取得できるようになっています。
  • テーブルを1つずつ戻って、100万行を見つけ、ステータスが「ONLINE」の行をフィルター処理します。
  • 最後に、クエリ結果を並べ替えます(500,000 行がすべてオンラインの場合は、これらの 500,000 行の並べ替えを続けます)。

最後に、データ量が大きいため、5 行のみが取得されますが、先ほど示した極端な例によれば、実際には 100 万行のデータが照会され、最終的にデータベースの 50 万行のメモリ ソートがメモリ内で実行されます。

したがって、非常に非効率的です。

最初のステップのクエリ プロセスを説明するために概略図が描かれています。ピンクの部分は、最終的にテーブルでクエリする必要があるデータ行を表します。

画像では、インデックス保存ルールに従って一部のデータを偽造して入力しました。何か間違っている点がありましたら、メッセージを残して指摘してください。この図を通して、共同インデックスストレージとインデックスクエリの方法を理解していただければ幸いです。

改善案1

範囲検索は、適切なインデックスでは使いにくいです。audit_time とstatusの結合インデックスを追加すると、どのような改善audit_time見られますか?

テーブル `th_content` を変更し、インデックス `idx_audit_status` (`audit_time`, `status`) を追加します。
mysql> explain select `id`, `title` from `th_content` where `audit_time` < 1541984478 and `status` = 'ONLINE' order by `audit_time` desc, `id` desc limit 5;
+----+--------------+------------+--------+------------------------------------------+------------------+--------+--------+------------+-------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+--------------+------------+--------+------------------------------------------+------------------+--------+--------+------------+-------------+
| 1 | SIMPLE | th_content | range | idx_at_ft_pt_let、idx_audit_status | idx_audit_status | 4 | NULL | 209754 | where の使用 |
+----+--------------+------------+--------+------------------------------------------+------------------+--------+--------+------------+-------------+

詳細: audit_timeは範囲検索なので、2 番目の列のインデックスは使用されません。audit_time のみ使用できるため、 audit_time key_len 4 になります。次のアイデア 2 では、これら 2 つのフィールドkey_len依然として 5 です。

インデックスを追加した後の実行プロセスを分析してみましょう。

  • ジョイントインデックスから監査時間より短い最大のaudit_timeを持つ行のジョイントインデックスを見つけます。
  • 次に、 < audit_timeは範囲検索であり、2 番目の列のインデックスの値が分散しているため、1 つずつ下方向に検索します。したがって、5 行目が取得されるまで、条件 ( status = 'ONLINE') を満たすインデックス行を 1 つずつ前方検索して一致させる必要があります。
  • 必要な特定のデータを照会するにはテーブルに戻ります

上の図では、ピンク色は最初の列のインデックス要件を満たす行を示しています。1 つずつ前方にクエリを実行すると、このリーフ ノードに 3 つのレコードが見つかります。次に、前のリーフ ノードで左方向にクエリを続行する必要があります。レコードに一致する 5 行が見つかるまで、最終的にテーブルに戻ります。

改善点

status値はインデックス内にあるため、 status = 'ONLINE' を満たす行をフィルタリングするときに、クエリのためにテーブルに戻る必要はありません。テーブルに戻ると、 5 行のデータのみがクエリされるため、 iopsが大幅に削減されます。

この指標の欠点

idx_audit_statusでスキャンされた 5 行すべてstatusONLINEの場合、スキャンする必要があるのは 5 行のみです。

idx_audit_statusでスキャンされた最初の 100 万行のうち、 statusONLINEである行が 4 行のみの場合、必要な 5 行を取得するには 100 万 1 行をスキャンする必要があります。インデックスは不確定な数の行をスキャンする必要があります。

改善案2

テーブル `th_content` を変更し、インデックス `idx_audit_status` を削除します。
テーブル `th_content` を変更し、インデックス `idx_status_audit` (`status`, `audit_time`) を追加します。 

こうすることで、仕分けするときもテーブルに戻すときもプレッシャーがかかりません。

要約する

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。これについてもっと知りたい場合は、次のリンクをご覧ください。

以下もご興味があるかもしれません:
  • MySQL ジョイントインデックス(複合インデックス)の実装
  • MySQL フルテキスト インデックス、ジョイント インデックス、Like クエリ、JSON クエリのうち、どれが高速ですか?
  • MySQLジョイントインデックスの左端一致原則の詳細な分析
  • MySQLのジョイントインデックス機能の分析と使用例
  • MySQL ジョイントインデックスの使用例
  • MySQL のジョイントインデックス学習チュートリアル
  • MySQL のジョイントインデックスと Where 句を最適化してデータベース操作の効率を向上
  • MySQL 独立インデックスと共同インデックスの選択

<<:  VMware 15.5 に CentOS7 をインストールするためのグラフィック チュートリアル

>>:  JavaScriptのスタックとコピーの詳細な説明

推薦する

英語のシングルクォーテーション「''」を含むSQLの記述の失敗について徹底解説

問題が発生しました。情報の編集をテストする際、編集した内容に一重引用符 (') が含まれてい...

MySQL の制限使用法とページングクエリステートメントのパフォーマンス分析の詳細な説明

使用制限クエリ ステートメントを使用する場合、多くの場合、データの最初の数行または中間行を返す必要が...

JavaScript シングルスレッドと非同期の詳細

目次1. タスクキュー2. 混乱を招く問題を説明する1. setTimeout(f1,0)とは何です...

Django2.* + Mysql5.7 開発環境統合チュートリアル図

環境: 10.12 の新機能Python 3.6 MySQL 5.7.25 の場合ジャンゴ 2.2....

CSS3 における擬似クラスの一般的な使用法の詳細な説明

before/after 疑似クラスは、要素内に 2 つの追加タグを挿入するのと同じです。最も適した...

Mysql トランザクション分離レベルの読み取りコミットの詳細な説明

MySQL トランザクション分離レベルを表示する mysql> '%isolation...

Linuxの同時実行は簡単です。このようにするだけです

並行処理関数 i の `grep server /etc/hosts | awk '{pri...

共有サイドバーを実装するためのネイティブJS

この記事では、ネイティブ JS で実装された共有サイドバーを紹介します。効果は次のとおりです。 以下...

ElementuiはデータをxlsxとExcelテーブルにエクスポートします

最近、Vue プロジェクトについて知り、ElementUI でデータを xlsx および Excel...

MySQL 8.0.13 のインストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 8.0.13のインストールと設定のチュートリアルを参考までに紹介します。具...

Jenkins の紹介と Docker で Jenkins をデプロイする方法

1. 関連概念1.1 Jenkins の概念: Jenkins は、使用されるプラットフォームに関係...

MySQL のスロークエリの方法と例

1. はじめにスロークエリログを有効にすると、MySQL は指定された時間を超えるクエリステートメン...

Linux 上での Go 環境の構築のインストールと設定の説明

Linux で Go 環境を構築するのは非常に簡単です。 1. go1.2.1.linux-386....

CSS3 での 2D および 3D 変換の実装

CSS3 は、要素の 2D 平面変換と視覚的な 3D 空間変換を実装します。2D 変換はより頻繁に使...

MySQLのファジークエリの要約

1. 一般的な使用法: (1)%で使用する% は 1 つ以上の文字のワイルドカードを表します。たとえ...