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のスタックとコピーの詳細な説明

推薦する

Linux で MySQL のデフォルト エンコーディングを変更する方法

開発プロセス中に、MySQL データベースを復元した後にデータベース データに文字化けが発生した場合...

Linux での Docker と portainer の設定方法

1.Docer CEをインストールして使用するこの記事では、CentOS 7 を例に Docker ...

JavaScript Reduceの詳しい説明

目次地図フィルターいくつかの毎インデックスを検索パイプ参考回答1. パラメータを受け入れる関数を返す...

WeChat ミニプログラム ユーザー認証のベストプラクティス ガイド

序文WeChat アプレットを開発する際には、ユーザーの権限が必要なページを使用する必要があることが...

CentOS 8 システム FTP サーバーのインストールとパッシブ モードの設定の詳細なチュートリアル

目次1. 基本を理解する2. システム環境を確認する3. ftpコマンドをインストールする[オプショ...

EclipseにTomcatサーバー設定を追加する方法

1. ウィンドウ -> 設定を選択してEclipseの設定パネルを開きます。 2. 「設定」ウ...

mysql5.7.19 winx64 インストールおよび構成方法のグラフィック チュートリアル (win10)

mysql 5.7.19 winx64のインストールチュートリアルは以下のように記録され、みんなと...

CSS を使用して適応型の幅と高さを持つ 16:9 の長方形を実装する例

先ほど、適応幅と高さが1:1の正方形を作成する方法について説明しました。 https://www.j...

Windows 10 で MySQL をダウンロードするための詳細なチュートリアル

MySQL のバージョンは、Enterprise Edition と Community Editi...

Linux での nginx のインストール、展開、使用方法の詳細な説明

目次1. ダウンロード2. 展開3. Nginxログ関連の設定4. ファイルダウンローダーとして n...

ミニプログラムはミニプログラムクラウドを使用してWeChatの支払い機能を実装します

目次1. WeChat Payを開く1.1 アフィリエイト加盟店番号1.2 加盟店番号を追加する1....

Alibaba Cloud ESC に MYSQL8.0 をインストールするチュートリアル

接続ツールを開きます。私はMobaXterm_Personal_12.1を使用します(公式サイトのダ...

CocosCreator 学習モジュールスクリプト

Cocos Creator モジュラースクリプトCocos Creator を使用すると、コードを複...

JavaScript セレクター関数 querySelector および querySelectorAll

目次1. querySelectorは単一の要素を照会する1. ドキュメントインスタンスの呼び出し2...

検索エンジンのウェブサイトの入り口の無料コレクション

1: Baiduウェブサイトログイン入口ウェブサイト: http://www.baidu.com/s...