序文 「High Performance MySQL」では、インデックスでは範囲フィールドの後の部分が無効であるため (ICP を考慮する必要がある)、in メソッドを使用すると、特定の範囲クエリを効果的に置き換えてクエリの効率を向上できると説明されています。 MySQL オプティマイザーは、クエリをクエリ用の n*m の組み合わせに変換し、最後に返された値をマージします。これは、union に似ていますが、より効率的です。 IN() の組み合わせ条件が多すぎると、MySQL では多くの問題が発生します。クエリの最適化には長い時間がかかり、大量のメモリを消費する可能性があります。新しいバージョンの MySQL では、組み合わせの数が一定数を超えるとプラン評価が実行されないため、MySQL がインデックスを有効に活用できない可能性があります。 ここでの特定の数は、MySQL 5.6.5 以降のバージョンではパラメータ eq_range_index_dive_limit によって制御されます。デフォルト設定は10で、バージョン5.7以降は200に変更されました。もちろん手動で設定することも可能です。 5.6 マニュアルには次のように記載されています。
言い換えると、 eq_range_index_dive_limit = 0 インデックスダイブのみ使用可能 0 < eq_range_index_dive_limit <= N インデックス統計を使用する eq_range_index_dive_limit > N: インデックスダイブのみ使用可能 MySQL 5.7 では、IN() リストの数が 10 を超えることが多いため、範囲等価演算 (IN()) の実行プランが可能な限り正確になるように、デフォルト値が 10 から 200 に変更されました。 MySQL の公式マニュアルには次のような一文があります。
本旨:
推定方法は 2 つあります。
これら2つの方法を比較する
簡単に言うと、オプション eq_range_index_dive_limit の値は、IN リスト内の条件の数の上限を設定します。値を超えると、実行プランはインデックス ダイブからインデックス統計に変更されます。 なぜこれら 2 つの方法を区別する必要があるのでしょうか?
ディスカッショントピック
範囲クエリとインデックスの使用 SQL は次のとおりです。 SELECT * FROM pre_forum_post WHERE tid=7932552 AND invisible IN('0','-2') ORDER BY dateline DESC LIMIT 10; インデックスは次のとおりです。 PRIMARY(tid,位置), pid(pid)、 fid(tid)、 表示順序(tid,非表示,日付行) 最初(tid,最初) new_auth(authorid、invisible、tid) idx_dt(日付行) mul_test(tid,invisible,dateline,pid) 実行計画を見てみましょう: root@localhost 16:08:27 [ultrax]> SELECT * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') を説明します -> ORDER BY dateline DESC LIMIT 10; +----+-------------+----------------+-------+--------------------------------------------------------+--------------+---------+------+------+---------------------------------------+ | id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 | +----+-------------+----------------+-------+--------------------------------------------------------+--------------+---------+------+------+---------------------------------------+ | 1 | SIMPLE | pre_forum_post | range | PRIMARY,displayorder,first,mul_test,idx_1 | displayorder | 4 | NULL | 54 | インデックス条件の使用; filesort の使用 | +----+-------------+----------------+-------+--------------------------------------------------------+--------------+---------+------+------+---------------------------------------+ セット内の 1 行 (0.00 秒) MySQL オプティマイザは、これは範囲クエリであると認識するため、(tid、invisible、dateline) インデックスの dateline フィールドは確実に使用されません。つまり、この SQL の最終的なソートでは、インデックス内で直接ソート アクションを完了するのではなく、一時的な結果セットが生成され、その後結果セット内でソートが完了します。そこで、インデックスを追加しようとしました。 root@localhost 16:09:06 [ultrax]> テーブル pre_forum_post を変更し、インデックス idx_1 (tid,dateline) を追加します。 クエリは正常、20374596 行が影響を受け、警告は 0 件 (600.23 秒) レコード: 0 重複: 0 警告: 0 root@localhost 16:20:22 [ultrax]> explain SELECT * FROM pre_forum_post force index (idx_1) WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10; +----+-------------+----------------+------+---------------+--------+---------+---+-------------+-------------+ | id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 | +----+-------------+----------------+------+---------------+--------+---------+---+-------------+-------------+ | 1 | SIMPLE | pre_forum_post | ref | idx_1 | idx_1 | 3 | const | 120646 | where の使用 | +----+-------------+----------------+------+---------------+--------+---------+---+-------------+-------------+ セット内の 1 行 (0.00 秒) root@localhost 16:22:06 [ultrax]> SELECT sql_no_cache * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10; ... 10 行セット (0.40 秒) root@localhost 16:23:55 [ultrax]> SELECT sql_no_cache * FROM pre_forum_post force index (idx_1) WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10; ... セット内の行数は 10 です (0.00 秒) 実験により、その効果は優れていることが証明されました。実際、理解するのは難しくありません。上で述べたように、in() は MySQL オプティマイザでさまざまな組み合わせでデータを取得します。ソートやグループが追加された場合、一時的な結果セットに対してのみ操作できます。つまり、インデックスにソートやグループ フィールドが含まれていても、それはまだ役に立ちません。唯一の不満は、MySQL オプティマイザーの選択がまだ十分に信頼できないことです。
eq_range_index_dive_limit の説明 上記の例を引き続き使用する場合、idx_1 を直接使用できないのはなぜですか?このインデックスのみを強制的に使用するにはヒントを使用する必要がありますか?ここではまず、eq_range_index_dive_limit の値を確認します。 root@localhost 22:38:05 [ultrax]> 'eq_range_index_dive_limit' のような変数を表示します。 +---------------------------+-------+ | 変数名 | 値 | +---------------------------+-------+ | 等価範囲インデックスダイブ制限 | 2 | +---------------------------+-------+ セット内の 1 行 (0.00 秒) 前述の状況によると、0 < eq_range_index_dive_limit <= N はインデックス統計を使用するので、OPTIMIZER_TRACE を使用して確認してみましょう。 { "インデックス": "表示順序", 「範囲」: [ 「7932552 <= tid <= 7932552 かつ -2 <= 非表示 <= -2」、 「7932552 <= tid <= 7932552 かつ 0 <= 非表示 <= 0」 ]、 "index_dives_for_eq_ranges": false, "rowid_ordered": 偽、 "using_mrr": 偽、 "index_only": 偽、 「行」: 54, 「コスト」: 66.81, 「選択済み」: true } // インデックス ダイブは false で、最終的に選択されたものは true です ... { "インデックス": "idx_1", 「範囲」: [ 「7932552 <= tid <= 7932552」 ]、 "index_dives_for_eq_ranges": true、 "rowid_ordered": 偽、 "using_mrr": 偽、 "index_only": 偽、 「行数」: 120646, 「コスト」: 144776, 「選択」:偽、 「原因」:「コスト」 } displayorder インデックスのコストは 66.81 であるのに対し、idx_1 のコストは 120646 であり、最終的に MySQL オプティマイザーは displayorder インデックスを選択することがわかります。したがって、eq_range_index_dive_limit を > N に設定する場合、より正確な実行プランを取得するためにインデックス ダイブ計算方法を使用する必要がありますか? root@localhost 22:52:52 [ultrax]> eq_range_index_dive_limit を 3 に設定します。 クエリは正常、影響を受けた行は 0 行 (0.00 秒) root@localhost 22:55:38 [ultrax]> explain SELECT * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10; +----+-------------+----------------+------+------------------------------------------+--------+---------+---+-------------+-------------+ | id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 | +----+-------------+----------------+------+------------------------------------------+--------+---------+---+-------------+-------------+ | 1 | SIMPLE | pre_forum_post | ref | PRIMARY,displayorder,first,mul_test,idx_1 | idx_1 | 3 | const | 120646 | where の使用 | +----+-------------+----------------+------+------------------------------------------+--------+---------+---+-------------+-------------+ セット内の 1 行 (0.00 秒) optimize_traceの結果は次のとおりです。 { "インデックス": "表示順序", 「範囲」: [ 「7932552 <= tid <= 7932552 かつ -2 <= 非表示 <= -2」、 「7932552 <= tid <= 7932552 かつ 0 <= 非表示 <= 0」 ]、 "index_dives_for_eq_ranges": true、 "rowid_ordered": 偽、 "using_mrr": 偽、 "index_only": 偽、 「行数」: 188193, 「コスト」: 225834, 「選択済み」: true } ... { "インデックス": "idx_1", 「範囲」: [ 「7932552 <= tid <= 7932552」 ]、 "index_dives_for_eq_ranges": true、 "rowid_ordered": 偽、 "using_mrr": 偽、 "index_only": 偽、 「行数」: 120646, 「コスト」: 144776, 「選択済み」: true } ... 「プランの費用」: 144775, "計画行数": 120646, 「選択済み」: true 代替インデックス選択では、両方のインデックスが選択され、最終的な論理最適化では、コストが最も低いインデックス idx_1 が選択されます。上記は、等範囲クエリの eq_range_index_dive_limit の値が MySQL オプティマイザの計算オーバーヘッドに影響し、それによってインデックス選択に影響を与えることを示しています。さらに、プロファイリングを使用して、オプティマイザの統計的な時間消費を確認することもできます。 インデックスダイブ +----------------------+----------+ | ステータス | 期間 | +----------------------+----------+ | 開始 | 0.000048 | | 権限を確認中 | 0.000004 | | オープニングテーブル | 0.000015 | | 初期化 | 0.000044 | | システムロック | 0.000009 | | 最適化 | 0.000014 | | 統計 | 0.032089 | | 準備中 | 0.000022 | | ソート結果 | 0.000003 | | 実行中 | 0.000003 | | データ送信中 | 0.000101 | | 終了 | 0.000004 | | クエリ終了 | 0.000002 | | テーブルのクローズ | 0.000009 | | アイテムを解放 | 0.000013 | | クリーンアップ | 0.000012 | +----------------------+----------+ インデックス統計 +----------------------+----------+ | ステータス | 期間 | +----------------------+----------+ | 開始 | 0.000045 | | 権限を確認中 | 0.000003 | | オープニングテーブル | 0.000014 | | 初期化 | 0.000040 | | システムロック | 0.000008 | | 最適化 | 0.000014 | | 統計 | 0.000086 | | 準備中 | 0.000016 | | ソート結果 | 0.000002 | | 実行中 | 0.000002 | | データ送信中 | 0.000016 | | ソートインデックスを作成しています | 0.412123 | | 終了 | 0.000012 | | クエリ終了 | 0.000004 | | テーブルのクローズ | 0.000013 | | アイテムを解放 | 0.000023 | | クリーンアップ | 0.000015 | +----------------------+----------+ eq_range_index_dive_limit を増やしてインデックス ダイブを使用すると、オプティマイザ統計は ndex 統計方法よりも大幅に時間がかかりますが、最終的にはより合理的な実行プランが使用されることがわかります。統計時間は 0.032089 秒対 0.000086 秒ですが、SQL 実行時間は 0.41 秒対 0.03 秒程度です。 添付ファイル: optimize_traceの使い方 optimizer_trace を 'enabled=on' に設定します。 information_schema.optimizer_trace\G から * を選択
プロフィールの使い方 プロファイリングをONに設定します。 SQLを実行します。 プロフィールを表示します。 クエリ2のプロファイルを表示します。 クエリ 2 のプロファイル ブロック io、cpu を表示します。 メモリ、スワップ、コンテキストスイッチ、ソースなどの情報も表示できます。 参考文献 [1]MySQL SQL最適化シリーズ: INクエリとRANGEクエリ https://www.jb51.net/article/201251.htm [2]MySQL物理クエリ最適化技術---インデックスダイブ分析 http://blog.163.com/li_hx/blog/static/18399141320147521735442/ これで、インクエリと範囲クエリに関する SQL 最適化チュートリアルに関するこの記事は終了です。インクエリと範囲クエリに関するより関連性の高い SQL 最適化コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
>>: Vue3における非親子コンポーネント通信の詳細な説明
最近、私たちの小さなチームは、サーバー上の共有フォルダーを共有して、全員がパブリックリソースドキュメ...
Linux では、すべてがファイルであり (ディレクトリもファイルです)、各ファイルにはユーザーに対...
1. nginx.conf の http{} に次のコードを追加します。 limit_conn_zo...
序文:インストール プロセスについては詳しく説明しません。問題に直接触れましょう。MySQL のリモ...
仕事ではリモート サーバーが必要になることが多く、次の 2 つの問題に遭遇することがよくあります。 ...
平日はニュースに注目して、テンセントをよく閲覧しています。しかし、コメントへの返信はほとんど見られま...
目次1. インデックスの基本1. インデックスの種類1.1 Bツリーインデックス1.2 ハッシュイン...
この記事では、MySQL 8.0.16 winx64のインストールと設定の具体的な方法を記載します。...
この記事では、Baidu News Navigation Barの効果を実現するための具体的なJSコ...
開発に Vue を使用する場合、次のような状況に遭遇することがあります。Vue インスタンスを生成し...
フロントエンドとバックエンドがやり取りする場合、get または delete を介してバックエンドに...
目次概要1. フックの呼び出し順序2. onChangesフック3. 変更検出メカニズムとDoChe...
ローカルでコンテナを作成した後、このコンテナに基づいてローカル イメージを作成し、このイメージを D...
目次1. 再帰とは何ですか? 2. 再帰を使って数学の問題を解く1. 1 * 2 * 3 * 4 …...
以下のインストールではすべて、インストール ルート ディレクトリとして ~/ ディレクトリが使用され...