この SQL 書き込み方法では本当にインデックスが失敗するのでしょうか?

この SQL 書き込み方法では本当にインデックスが失敗するのでしょうか?

序文

インターネット上には、MySQL でインデックスにヒットできないさまざまな状況をまとめた記事がよくあります。その 1 つは、またはを使用するステートメントがインデックスにヒットできないというものです。

この記述は実際には正しくありません。正しい結論は、MySQL 5.0 以降では、またはで接続されたフィールドに独立したインデックスがある場合、そのインデックスにヒットできるということです。ここで、index_merge 機能が使用されます。

MySQL 5.0 より前では、SQL ステートメントは 1 つのインデックスしか使用できません。SQL ステートメントで or キーワードを使用すると、既存のインデックスは無効になり、テーブル全体のスキャンが実行されます。どのインデックスを使用しても、MySQL は条件を満たすデータを一度に見つけることができないため、インデックスを放棄することしかできません。

MySQL も継続的にアップグレードおよび更新されており、MySQL バージョン 5.0 以降では index_merge インデックス マージ機能が追加され、1 つの SQL で複数のインデックスを使用することも可能になりました。

index_merge の基本的な考え方は、まず単一のインデックスを使用して要件を満たすデータを見つけ、次にそれらのデータを結合して返すことです。
例を見てみましょう。

ここでも前回の記事で作成したテーブルとテストデータを使用します。10w のテストデータがテーブルに挿入されます。テーブル構造は次のとおりです。

テーブル `t` を作成します (
 `id` int(11) NULLではない、
 `a` int(11) デフォルト NULL,
 `b` int(11) デフォルト NULL,
 主キー (`id`)
)ENGINE=InnoDB;

まず a フィールドにインデックスを追加し、次に または を使用してクエリ ステートメントを実行して、それがどのように機能するかを確認しましょう。

mysql> テーブル t を変更し、インデックス a_index(a) を追加します。
クエリは正常、影響を受けた行は 0 行 (0.17 秒)
レコード: 0 重複: 0 警告: 0
mysql> explain select a from t where a=100 or b=6000;
+----+-------------+-------+-------+---------------+-------+--------+---------+------------+------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+---------------+-------+--------+---------+------------+------------+
| 1 | SIMPLE | t | ALL | a_index | NULL | NULL | NULL | 100332 | where の使用 |
+----+-------------+-------+-------+---------------+-------+--------+---------+------------+------------+
セット内の 1 行 (0.00 秒)

フィールド b にはインデックスがないため、MySQL はテーブルを返すプロセスを回避できるため、完全なテーブル スキャンの方がコストがかからないと判断します。

次に、フィールド b にインデックスを追加して、SQL ステートメントを再度実行します。

mysql> テーブル t を変更し、インデックス b_index(b) を追加します。
クエリは正常、影響を受けた行は 0 行 (0.17 秒)
レコード: 0 重複: 0 警告: 0
mysql> explain select a from t where a=100 or b=6000;
+----+-------------+-------------+------------+-----------------+--------+------+------+-------------------------------------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------------+------------+-----------------+--------+------+------+-------------------------------------------+
| 1 | SIMPLE | t | index_merge | a_index,b_index | a_index,b_index | 5,5 | NULL | 2 | union(a_index,b_index); を使用する where を使用する |
+----+-------------+-------------+------------+-----------------+--------+------+------+-------------------------------------------+
セット内の 1 行 (0.00 秒)

今回は、MySQL がインデックス a と b の両方を使用し、type フィールドの値が index_merge であることがわかります。

次に、別の SQL ステートメントを見て、結果がどうなるかを確認してみましょう。

mysql> explain select a from t where a>100 or b>6000;
+----+-------------+-------+-------+-----------------+-------+--------+--------+-----------+------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+-----------------+-------+--------+--------+-----------+------------+
| 1 | SIMPLE | t | ALL | a_index,b_index | NULL | NULL | NULL | 100332 | where の使用 |
+----+-------------+-------+-------+-----------------+-------+--------+--------+-----------+------------+
セット内の 1 行 (0.00 秒)

この SQL 文は、等号を大なり記号に変更するだけなので、返される結果セットは間隔セットになります。MySQL はここでインデックスを放棄し、テーブル全体のスキャンを実行します。ただし、いくつかの記事で、この問題は MySQL バージョン 5.7 以降で最適化されている、つまり、間隔クエリでも index_merge がサポートされていると読みました。私のバージョンは 5.6 で、この最適化はまだ検証していません。興味があれば、検証してみてください。

実際、MySQL には絶対的なことがたくさんあります。MySQL のバージョンが異なれば、同じ SQL に対しても内部処理方法が異なる場合があります。同時に、MySQL は継続的に最適化およびアップグレードされており、古い知識ポイントの一部は簡単に適用できなくなることがわかります。

この記事が皆さんのお役に立てば幸いです。フォローして「いいね!」していただければ、私にとって最高のサポートになります。ありがとうございます。

また、MySQL の基盤となるデータ構造については、私が以前に書いた他の記事を参照すると、この記事の理解に役立つかもしれません。

要約する

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。

以下もご興味があるかもしれません:
  • Mysql インデックスが失敗するいくつかの状況の分析
  • MySQL インデックス障害の 5 つの状況の分析
  • MySQL でデータベース インデックスが失敗する状況の詳細な分析
  • mysql はインデックスを無効にしますか?

<<:  CentOS7 は Docker のバージョン 19 をデプロイします (簡単なので、従ってください)

>>:  WeChatアプレットで計算機機能を実装する

推薦する

MySQLパーティションテーブルは月別に分類されています

目次テーブルを作成するデータベース ファイルを表示します。入れるクエリ消去補足:Mysqlは月テーブ...

vue_drf は SMS 認証コードを実装します

目次1. 需要1. 需要2. SDKパラメータ設定1. ディレクトリ構造3. コードの実装1. バッ...

border-radiusは要素に丸い境界線を追加する方法です

border-radius:10px; /* すべての角は半径 10px で丸められます*/ bor...

mysql5.7.19 winx64 解凍版のインストールと設定のチュートリアル

mysql 5.7.19 winx64解凍版のインストールチュートリアルを収録しました。具体的な内容...

MySql 5.7.20 のインストールとデータおよび my.ini ファイルの構成

1. まずMySqlの公式サイトからダウンロードします参考: https://www.jb51.ne...

MySQLパスワードを変更するいくつかの方法

序文:データベースを日常的に使用すると、パスワードが単純すぎて変更する必要がある場合、パスワードの有...

燃える炎効果の英語フォント16種類をシェアする

私たちは視覚の世界に住んでおり、多くの視覚効果に囲まれています。コンピューターの前にいても、屋外にい...

hrefを使用すると、リンクをクリックするだけでページ上の特定の場所にジャンプできます。

ページ内の a タグをクリックした後、ページ内の対応する場所にジャンプするようにします。方法は非常に...

HTML テーブルタグチュートリアル (25): 垂直配置属性 VALIGN

垂直方向では、行の配置を上、中央、下に設定できます。基本的な構文<TR VALIGN=&quo...

div画像マーキーシームレス接続実装コード

コードをコピーコードは次のとおりです。 <html> <ヘッド> <ス...

Vue スキャフォールディング プロジェクトを作成するための詳細な手順

vue スキャフォールディング -> vue.cli大規模で完全に機能する Vue プロジェク...

MySQL ファントムリードとその排除方法の詳細な説明

目次トランザクション分離レベルファントムリーディングとは何ですか?ファントムリードを排除する方法要約...

ウェブサイトデザインの経験 ウェブサイト構築におけるよくある間違いのまとめ

注意: 計画、設計、開発のいずれの場合でも、これらの間違いは避けなければなりません。 1. ナビゲー...

jsはFileReaderを使用してローカルファイルまたはBLOBを読み取ります

目次FileReaderはローカルファイルまたはBLOBを読み取ります1. FileReaderの使...

2 級コンピュータ試験のための MySQL の知識ポイントとよく使用される MYSQL コマンド

2級コンピュータ試験のMySQL知識ポイントの基礎、一般的なMYSQLコマンドは次のとおりです。よく...