目次
1. 準備作業
2. インデックス無効化ルール
上記の結合インデックスを引き継ぎ、次の SQL クエリを使用します:
4.计算、函数导致索引失效
5.类型转换导致索引失效
6.不等于(!= 或者<>)索引失效
7.is null可以使用索引,is not null无法使用索引
8.like以%开头,索引失效
9.OR前后存在非索引的列,索引失效
10.字符集不统一
三、建议
ホームページ データベース mysql チュートリアル MySQL がインデックス障害を引き起こす状況はどのようなものですか?

MySQL がインデックス障害を引き起こす状況はどのようなものですか?

Jun 03, 2023 pm 07:19 PM
mysql

    1. 準備作業

    まず、デモ用に 2 つのテーブルを準備します:

    CREATE TABLE `student_info` (
      `id` int NOT NULL AUTO_INCREMENT,
      `student_id` int NOT NULL,
      `name` varchar(20) DEFAULT NULL,
      `course_id` int NOT NULL,
      `class_id` int DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8;
    ログイン後にコピー
    CREATE TABLE `course` (
      `id` int NOT NULL AUTO_INCREMENT,
      `course_id` int NOT NULL,
      `course_name` varchar(40) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
    ログイン後にコピー
    #准备数据
    select count(*) from student_info;#1000000
    select count(*) from course;      #100
    ログイン後にコピー

    2. インデックス無効化ルール

    # 1. 結合インデックスの使用を優先します

    次の SQL ステートメントにはインデックスがありません:

    #平均耗时291毫秒
    select * from student_info where name=&#39;123&#39; and course_id=1 and class_id=1;
    ログイン後にコピー

    インデックスを作成することでクエリの効率を最適化します。次のようないくつかのオプションがあります:

    ①通常のインデックスを作成します:

    #建立普通索引
    create index idx_name on student_info(name);
    #平均耗时25毫秒,查看explain执行计划,使用到的是idx_name索引查询
    select * from student_info where name=&#39;MOKiKb&#39; and course_id=1 and class_id=1;
    ログイン後にコピー

    ②通常のインデックスを基に、結合インデックスを追加します:

    #name,course_id组成的联合索引
    create index idx_name_courseId on student_info(name,course_id);
    #该查询语句一般使用的是联合索引,而不是普通索引,具体看优化器决策
    #平均耗时20ms
    select * from student_info where name=&#39;zhangsan&#39; and course_id=1 and class_id=1;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか?

    ご覧のとおり、

    複数のインデックスを使用できる場合、システムは通常、より長いジョイント インデックスの使用を優先します。これは、ジョイント インデックスの方が高速であるためです。 これも同様です。理解するのは簡単です。 前提条件は、結合インデックス の左端の一致原則に従うことです。

    name、course_id、class_id で構成されるジョイント インデックスを作成する場合、上記の SQL ステートメントは、予想どおり、より長い key_len を持つこのジョイント インデックスを使用します (予期せず、オプティマイザーは他のより良いソリューションを選択する可能性があります。もっと早く)。

    ジョイント インデックスの速度は、通常のインデックスの速度より必ずしも優れているわけではありません。 たとえば、最初の条件ですべてのレコードをフィルタリングする場合、後続の条件を使用する必要はありません。索引。

    2. 左端の一致原理

    #删除前例创建的索引,新创建三个字段的联合索引,name-course_id-cass_id
    create index idx_name_cou_cls on student_info(name,course_id,class_id);
    ログイン後にコピー

    ① すべてのジョイント インデックスが一致する状況:

    #关联字段的索引比较完整
    explain select * from student_info where name=&#39;11111&#39; and course_id=10068 and class_id=10154;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか?各フィールドの条件はジョイント インデックスと一致するため、この SQL ステートメントは左端のプレフィックス ルールに従います。ジョイント インデックスを使用すると、高速な検索が可能になり、追加のクエリが回避されるため、これが最適な状況になります。

    ②ジョイント インデックスの右端の部分が欠落しています:

    explain select * from student_info where name=&#39;11111&#39; and course_id=10068;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか? SQL ステートメントの条件にジョイント インデックスのすべてが含まれていません。条件は一致しますが、右半分が消去されます。このステートメントで使用されるインデックスは関連クエリのままですが、その一部のみが使用されます。key_len を見ると、5 バイトが欠落していることがわかります。これらの 5 バイトは class_id に対応します。 class_id が有効ではないことを証明します (where にないので、当然使用されません)。

    同様に、where の course_id フィールドを消去すると、ジョイント インデックスは引き続き有効になりますが、key_len は減少します。

    ③ジョイント インデックスに欠落している状況:

    #联合索引中间的字段未使用,而左边和右边的都存在
    explain select * from student_info where name=&#39;11111&#39; and class_id=10154;;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか?上記の SQL ステートメントでは引き続きジョイント インデックスが使用されていますが、その key_len小さくなりました name フィールドのみがインデックスを使用します class_id フィールドは結合インデックス内にありますが、左端の一致原則に従っていないため GG になります。

    SQL ステートメント全体の実行プロセスは次のとおりです。まず、ジョイント インデックスの B ツリー内で名前 11111 を持つすべてのレコードを検索し、次に class_id が 10154 ではないこれらのレコードの全文をフィルターで除外します。 。全文検索がもう一段階増えると、①や②よりもパフォーマンスが悪くなってしまいます。

    ④ジョイント インデックスの左端が欠落している状況:

    explain select * from student_info where class_id=10154 and course_id=10068;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか? この状況は、前の例の特殊なケースです。結合インデックスの左端が欠落している 左側のフィールドが見つからないため、他にもあるが全て無効となり全文検索となる。

    結論: 左端一致の原則は、クエリがインデックスの左端の列から開始され、インデックス内の列をスキップできないことを意味します。列がスキップされた場合、インデックスは部分的に無効になります。 (以下のすべてのフィールドのインデックスは無効です)。

    注: 結合インデックスを作成する場合、フィールドの順序は固定されており、左端の一致がこの順序に従って比較されますが、クエリ ステートメントではフィールドの順序が異なります。 where 条件はオプションです。変更とは、where 条件にインデックス フィールドが存在する限り、関連するインデックス フィールドの順序に従う必要がないことを意味します。

    3. 範囲条件の右側の列インデックスが無効です

    上記の結合インデックスを引き継ぎ、次の SQL クエリを使用します:

    #key_len=> name:63,course_id:5,class_id:5
    explain select * from student_info where name=&#39;11111&#39; and course_id>1 and class_id=1;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか? key_len は 68 のみです。これは、関連付けられたインデックスの class_id が使用されないことを意味します。これは左端の一致原則に従いますが、

    > 記号により右側のインデックスが作成されます。関連するインデックスの条件フィールドの値が無効です。

    ただし、>= 記号を使用した場合:

    #不是>、<,而是>=、<=
    explain select * from student_info where name=&#39;11111&#39; and course_id>=20 and course_id<=40 and class_id=1;
    ログイン後にコピー

    右側のインデックスは無効ではなく、key_len は 73 で、すべてのインデックスが無効になります。フィールドが使用されます。 MySQL がインデックス障害を引き起こす状況はどのようなものですか?

    结论:为了充分利用索引,我们有时候可以将>、<等价转为>=、<=的形式,或者将可能会有<、>的条件的字段尽量放在关联索引靠后的位置。

    4.计算、函数导致索引失效

    #删除前面的索引,新创建name字段的索引,方便演示
    create index idx_name on student_info(name);
    ログイン後にコピー

    现有一个需求,找出name为li开头的学生信息:

    #使用到了索引
    explain select * from student_info where name like &#39;li%&#39;;
    #未使用索引,花费时间更久
    explain select * from student_info where LEFT(name,2)=&#39;li&#39;;
    ログイン後にコピー

    上面的两条sql语句都可以满足需求,然而第一条语句用了索引,第二条没有,一点点的改变真是天差地别。

    结论:字段使用函数会让优化器无从下手,B树中的值和函数的结果可能不搭边,所以不会使用索引,即索引失效。字段能不用就不用函数。

    类似:

    #也不会使用索引
    explain select * from student_info where name+&#39;&#39;=&#39;lisi&#39;;
    ログイン後にコピー

    类似的对字段的运算也会导致索引失效。

    5.类型转换导致索引失效

    #不会使用name的索引
    explain select * from student_info where name=123;
    #使用到索引
    explain select * from student_info where name=&#39;123&#39;;
    ログイン後にコピー

    如上,name字段是VARCAHR类型的,但是比较的值是INT类型的,name的值会被隐式的转换为INT类型再比较,中间相当于有一个将字符串转为INT类型的函数。

    6.不等于(!= 或者<>)索引失效

    #创建索引
    create index idx_name on student_info(name);
    #索引失效
    explain select * from student_info where name<>&#39;zhangsan&#39;;
    explain select * from student_info where name!=&#39;zhangsan&#39;;
    ログイン後にコピー

    不等于的情况是不会使用索引的。因为!=代表着要进行全文的查找,用不上索引。

    7.is null可以使用索引,is not null无法使用索引

    #可以使用索引
    explain select * from student_info where name is null;
    #索引失效
    explain select * from student_info where name is not null;
    ログイン後にコピー

    和前一个规则类似的,!=null。同理not like也无法使用索引。

    最好在设计表时设置NOT NULL约束,比如将INT类型的默认值设为0,将字符串默认值设为''

    8.like以%开头,索引失效

    #使用到了索引
    explain select * from student_info where name like &#39;li%&#39;;
    #索引失效
    explain select * from student_info where name like &#39;%li&#39;;
    ログイン後にコピー

    只要以%开头就无法使用索引,因为如果以%开头,在B树排序的数据中并不好找。

    9.OR前后存在非索引的列,索引失效

    #创建好索引
    create index idx_name on student_info(name);
    create index idx_courseId on student_info(course_id);
    ログイン後にコピー

    如果or前后都是索引:

    #使用索引
    explain select * from student_info where name like &#39;li%&#39; or course_id=200;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか?

    如果其中一个没有索引:

    explain select * from student_info where name like &#39;li%&#39; or class_id=1;
    ログイン後にコピー

    MySQL がインデックス障害を引き起こす状況はどのようなものですか?

    那么索引就失效了,假设还是使用索引,那就变成了先通过索引查,然后再根据没有的索引的字段进行全表查询,这种方式还不如直接全表查询来的快。

    10.字符集不统一

    字符集如果不同,会存在隐式的转换,索引也会失效,所有应该使用相同的字符集,防止这种情况发生。

    三、建议

    • 对于单列索引,尽量选择针对当前query过滤性更好的索引

    • 在选择组合索引时,query过滤性最好的字段应该越靠前越好

    • 在选择组合索引时,尽量选择能包含当前query中where子句中更多字段的索引

    • 在选择组合索引时,如果某个字段可能出现范围查询,尽量将它往后放

    以上がMySQL がインデックス障害を引き起こす状況はどのようなものですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    phpmyadminを開く方法 phpmyadminを開く方法 Apr 10, 2025 pm 10:51 PM

    次の手順でphpmyadminを開くことができます。1。ウェブサイトコントロールパネルにログインします。 2。phpmyadminアイコンを見つけてクリックします。 3。MySQL資格情報を入力します。 4.「ログイン」をクリックします。

    MySQL:世界で最も人気のあるデータベースの紹介 MySQL:世界で最も人気のあるデータベースの紹介 Apr 12, 2025 am 12:18 AM

    MySQLはオープンソースのリレーショナルデータベース管理システムであり、主にデータを迅速かつ確実に保存および取得するために使用されます。その実用的な原則には、クライアントリクエスト、クエリ解像度、クエリの実行、返品結果が含まれます。使用法の例には、テーブルの作成、データの挿入とクエリ、および参加操作などの高度な機能が含まれます。一般的なエラーには、SQL構文、データ型、およびアクセス許可、および最適化の提案には、インデックスの使用、最適化されたクエリ、およびテーブルの分割が含まれます。

    単一のスレッドレディスの使用方法 単一のスレッドレディスの使用方法 Apr 10, 2025 pm 07:12 PM

    Redisは、単一のスレッドアーキテクチャを使用して、高性能、シンプルさ、一貫性を提供します。 I/Oマルチプレックス、イベントループ、ノンブロッキングI/O、共有メモリを使用して同時性を向上させますが、並行性の制限、単一の障害、および書き込み集約型のワークロードには適していません。

    なぜMySQLを使用するのですか?利点と利点 なぜMySQLを使用するのですか?利点と利点 Apr 12, 2025 am 12:17 AM

    MySQLは、そのパフォーマンス、信頼性、使いやすさ、コミュニティサポートに選択されています。 1.MYSQLは、複数のデータ型と高度なクエリ操作をサポートし、効率的なデータストレージおよび検索機能を提供します。 2.クライアントサーバーアーキテクチャと複数のストレージエンジンを採用して、トランザクションとクエリの最適化をサポートします。 3.使いやすく、さまざまなオペレーティングシステムとプログラミング言語をサポートしています。 4.強力なコミュニティサポートを提供し、豊富なリソースとソリューションを提供します。

    MySQLの場所:データベースとプログラミング MySQLの場所:データベースとプログラミング Apr 13, 2025 am 12:18 AM

    データベースとプログラミングにおけるMySQLの位置は非常に重要です。これは、さまざまなアプリケーションシナリオで広く使用されているオープンソースのリレーショナルデータベース管理システムです。 1)MySQLは、効率的なデータストレージ、組織、および検索機能を提供し、Web、モバイル、およびエンタープライズレベルのシステムをサポートします。 2)クライアントサーバーアーキテクチャを使用し、複数のストレージエンジンとインデックスの最適化をサポートします。 3)基本的な使用には、テーブルの作成とデータの挿入が含まれ、高度な使用法にはマルチテーブル結合と複雑なクエリが含まれます。 4)SQL構文エラーやパフォーマンスの問題などのよくある質問は、説明コマンドとスロークエリログを介してデバッグできます。 5)パフォーマンス最適化方法には、インデックスの合理的な使用、最適化されたクエリ、およびキャッシュの使用が含まれます。ベストプラクティスには、トランザクションと準備された星の使用が含まれます

    Redis ExporterサービスでRedis Dropletを監視します Redis ExporterサービスでRedis Dropletを監視します Apr 10, 2025 pm 01:36 PM

    Redisデータベースの効果的な監視は、最適なパフォーマンスを維持し、潜在的なボトルネックを特定し、システム全体の信頼性を確保するために重要です。 Redis Exporter Serviceは、Prometheusを使用してRedisデータベースを監視するために設計された強力なユーティリティです。 このチュートリアルでは、Redis Exporterサービスの完全なセットアップと構成をガイドし、監視ソリューションをシームレスに構築します。このチュートリアルを研究することにより、完全に動作する監視設定を実現します

    SQLデータベースエラーを表示する方法 SQLデータベースエラーを表示する方法 Apr 10, 2025 pm 12:09 PM

    SQLデータベースエラーを表示する方法は次のとおりです。1。エラーメッセージを直接表示します。 2。エラーを表示し、警告コマンドを表示します。 3.エラーログにアクセスします。 4.エラーコードを使用して、エラーの原因を見つけます。 5.データベース接続とクエリ構文を確認します。 6.デバッグツールを使用します。

    Apacheのデータベースに接続する方法 Apacheのデータベースに接続する方法 Apr 13, 2025 pm 01:03 PM

    Apacheはデータベースに接続するには、次の手順が必要です。データベースドライバーをインストールします。 web.xmlファイルを構成して、接続プールを作成します。 JDBCデータソースを作成し、接続設定を指定します。 JDBC APIを使用して、接続の取得、ステートメントの作成、バインディングパラメーター、クエリまたは更新の実行、結果の処理など、Javaコードのデータベースにアクセスします。

    See all articles