MySQLの一般的なクエリ最適化手法の分析と要約

データの準備

CREATE TABLE staffs(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(24)NOT NULL DEFAULT'' COMMENT'姓名',
`age` INT NOT NULL DEFAULT 0 COMMENT'年龄',
`pos` VARCHAR(20) NOT NULL DEFAULT'' COMMENT'职位',
`add_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'入职时间'
)CHARSET utf8 COMMENT'员工记录表';

insert into staffs(NAME,age,pos,add_time) values('z3',22,'manager',NOW());
insert into staffs(NAME,age,pos,add_time) values('July',23,'dev',NOW());
insert into staffs(NAME,age,pos,add_time) values('2000',23,'dev',NOW());


create index idx_staffs_nameAgePos on staffs(name,age,pos)

1.複合インデックスは、左端のプレフィックス規則に従います

複数のケースにインデックスが付けられている場合は、左端のプレフィックスルールに従います。インデックスの左端の列から始まり、インデックスの列をスキップしないクエリを参照します。
ここに画像の説明を挿入
さらに、複合インデックスの場合、MySQLクエリは、インデックスの範囲条件の右側にある列を使用できません。つまり、範囲の後のインデックス列は無効です。

例:複合インデックスは、左端のプレフィックスルールに従いながら範囲条件を使用します。

EXPLAIN SELECT * FROM staffs where name = 'Alice' AND age > 21 AND pos = 'HR';

ここに画像の説明を挿入
key_len = 198は、nameとageの2つのインデックスのみが有効であり、後者のposはインデックスを使用しないことを示します。

範囲クエリを使用しない場合、複合クエリの実行プランは次
ここに画像の説明を挿入
のようになります。クエリレベルがrefに達し、名前、年齢、およびposインデックス列が使用されます。

2.インデックス付きの列には何もしないでください

インデックス付きの列で操作(計算、関数、(自動または手動)タイプ変換)を実行しないと、インデックスが失敗し、全表スキャンになります。
ここに画像の説明を挿入

ただし、照会する値に対して関数操作を使用すると、CONCAT関数を使用して文字列を連結するなど、通常はインデックスを使用できます。
ここに画像の説明を挿入

3.インデックスカバレッジを達成しようとします

インデックスをカバーする概念:インデックスカバーとも呼ばれ、選択のデータ列は、データ行を読み取らずにインデックスからのみ取得できます。MySQLは、インデックスを使用して、読み取りを行わなくても、選択リストのフィールドを返すことができます。インデックスに従って再びデータファイル。
ここに画像の説明を挿入

4.等しくない記号(!=または<>)を使用しないようにしてください

等しくない(!=または<>)を使用しているときにMySQLがインデックスを使用できないと、全表スキャンが発生します。したがって、WHERE句で!=または<>演算子を使用しないようにしてください。MySQLは、次の演算子にのみインデックスを使用します:<、<=、=、>、> =、BETWEEN、IN、場合によってはLIKE。
ここに画像の説明を挿入

5.nullおよびnullではないことを回避してください

nullとnull以外を使用すると、インデックスが使用できなくなります。WHERE句のフィールドでNULL値の判断を避けるようにしてください。テーブルを作成するときのデフォルト値はNULLですが、ほとんどの場合、NOTNULLを使用する必要があります。 、またはデフォルト値として0、-1などの特別な値を使用します。
ここに画像の説明を挿入

6.あいまいマッチングのように注意してください

ワイルドカード('$ abc ...')で開始するように、MySQLインデックスの失敗は全表スキャン操作
ここに画像の説明を挿入
になりますが、あいまい検索ではワイルドカードで開始する必要があるビジネスシナリオが常にあります。対応する解決策は、インデックスカバレッジを使用することです。つまり、クエリフィールドはプライマリキーやその他のインデックス付きフィールドにすることができるため、全表スキャンを回避できます。

簡単な例:
ここに画像の説明を挿入

7.またはを使用しないようにしてください

WHERE句で条件を結合するためにORを使用しないようにする必要があります。そうしないと、エンジンがインデックスの使用を断念し、全表スキャンを実行します。UNIONを使用して、次のようなクエリをマージできます。

select id from t where num=10 union all select id from t where num=20

ここに画像の説明を挿入
ユニオンクエリを使用します。
ここに画像の説明を挿入

8.データ型の問題に注意してください

データ型の問題に注意する必要があります。条件列が文字列の場合、暗黙の変換によるインデックスの無効化を避けるために、条件値は条件列の属性と同じである必要があります。

-知らせ:

  1. 条件列が文字列型で、条件値が数値の場合、インデックスは無効になります。

  2. ただし、条件列が整数で条件値が文字列の場合、インデックスは影響を受けません。
    ここに画像の説明を挿入
    ageは整数ですが、クエリ条件列で文字列が使用されている場合でも、インデックスは引き続き使用されます。
    ここに画像の説明を挿入

9.キーワード最適化による順序付け

9.1基本原則

ORDER BY句を使用して、Indexメソッドを使用してソートし、FileSortメソッドを使用してソートしないようにしてください。並べ替え操作は可能な限りインデックス列で実行されます。複合インデックスの場合は、インデックス作成に最適な左プレフィックスルールに従う必要があります。

9.2最適化戦略

1.sort_buffer_sizeパラメーターの設定を
増やします。2。max_length_for_sort_dataパラメーターの設定を増やします。
ここに画像の説明を挿入

9.3使用による注文の概要

MySQLには、ファイルソートまたはスキャン順インデックスソートの2つのソートがあります。MySQLは、ソートとクエリに同じインデックスを使用できます。
ここに画像の説明を挿入

10.キーワードの最適化によるグループ化

groupbyの本質は、最初に並べ替えてからグループ化することです。したがって、順序付けと同じ点に注意してください。インデックス列を使用できない場合は、max_length_for_sort_dataパラメーターの設定を増やし、sort_buffer_sizeパラメーターの設定を増やします。whereは持っているよりも高く、whereに記述できる条件は持っていることによって制限されません。

反例:

select * from order
group by user_id
having user_id <= 200;

この書き込み方法では、最初にユーザーIDに従ってすべての注文をグループ化し、次にユーザーIDが200以上のユーザーをフィルター処理する必要があります。グループ化は比較的時間のかかる操作であり、最初に、制限された条件でデータ範囲を狭める必要があります。

select * from order
where user_id <= 200
group by user_id;

11.unionをunionallに置き換えます

ユニオンクエリでunionキーワードを使用すると、重複排除されたデータを取得できます。union allキーワードを使用すると、重複データを含むすべてのデータを取得できます。重複排除のプロセスは、トラバース、ソート、および比較する必要があります。これは、すべてを結合するよりも時間がかかり、より多くのCPUリソースを消費します。

すべてを結合した後など、特別なシナリオがない限り、結果セットに重複データが表示され、ビジネスシナリオでは重複データが許可されない場合は、結合を使用できます。

12.インクリメンタルクエリ

通常の作業では、一部のデータを変更するためにデータベースをトラバースする必要があります。検索するデータの量が多い場合は、IDと時間で並べ替え、一度に1つのバッチのデータのみをクエリして、最大のIDを保存できます。このクエリの時間と時間。次のクエリ用に予約されています。
反例:

select * from order
where (查询条件)

正例:

select * from order
where id>#{lastId} and create_time >= #{lastCreateTime} (and 其他条件)
limit 100;

13.インデックスの数は可能な限り5を超えてはなりません

インデックスを使用すると、SQLのクエリのパフォーマンスを大幅に向上させることができますが、インデックスの数が多いほど優れています。新しいデータがテーブルに追加されると、同時にそのデータのインデックスを作成する必要があり、インデックスには追加のストレージスペースが必要であり、これには一定のパフォーマンスの消費が伴います。
MySQLは、B +ツリーの構造を使用してインデックスを保存します。挿入、更新、および削除操作中に、B+ツリーインデックスを更新する必要があります。インデックスが多すぎると、パフォーマンスが大幅に低下します。

アリババの開発者マニュアルでは、単一のテーブル内のインデックスの数は可能な限り5以内に制御する必要があり、単一のインデックス内のフィールドの数は5を超えてはならないことが規定されています。

では、インデックスの数を最適化する方法は?

  1. 共同インデックスを作成することはできますが、単一のキーインデックスを作成しないでください
  2. データベースまたはElasticSeach、HBase、MongoDBなどの検索エンジンを導入して、いくつかのクエリ関数を実現し、MySQLへのプレッシャーを軽減します

要約する

最後に、複合インデックスを列として、インデックスが特定のクエリ条件で使用されるかどうかのケースは次のとおりです
ここに画像の説明を挿入
。メモリを支援する式:
ここに画像の説明を挿入

拡張:
詳細なパフォーマンス最適化戦略:52SQLステートメントのパフォーマンス最適化戦略
https://juejin.cn/post/7028937747087753246

おすすめ

転載: blog.csdn.net/huangjhai/article/details/118662487