MySQLインデックスの最適化(1)


シミュレーションデータ

CREATE TABLE staffs(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(24) DEFAULT NULL 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());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES(NULL,23,'test',NOW());

ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(`name`,`age`,`pos`)

インデックスの順序を表示

ここに画像の説明を挿入


インデックス最適化の場合

  • 最良の左プレフィックスルール
  • フルマッチ
  • インデックス列では計算されません
  • スコープ後のすべての障害
  • カバーインデックスより多くの使用
  • 不平等な使用は無効になります
  • NULL値を使用する場合は注意してください
  • ファジークエリプラス右
  • 一重引用符付きの文字列
  • 使用または照会しないようにしてください

最良の左プレフィックスルール

インデックスの左端の列からクエリを開始し、インデックスの列をスキップしないでください

インデックスを使用するためのフィルター条件は、インデックスが作成された順序で満たされる必要があります。フィールドがスキップされると、インデックスの後のフィールドは使用できなくなります。

複数列のインデックスは、最初に最初の列に従って並べ替えられ、次に最初の列の並べ替え順序に基づいて2番目の列が並べ替えられます。最初の列がない場合は、2番目の列に直接アクセスし、2番目の列はなしである必要があります。次の列へのアクセスはインデックスを使用しません

インデックスで検索

EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' 
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age = 15 
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age = 15 and pos= 'dev'

ここに画像の説明を挿入

インデックス順以外のクエリ

EXPLAIN SELECT * FROM staffs WHERE age = 15 and pos= 'dev' --跳过第一个索引
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and pos= 'dev' -- 跳过第二个索引

ここに画像の説明を挿入

フルマッチ

クエリフィールドは順序に従ってインデックスで一致させることができ、速度は現時点で最速です。

インデックス列では計算されません

インデックス列に対して操作(計算、関数、(自動または手動)型変換)を実行しないでください。インデックスが失敗し、全表スキャンになる可能性があります。

EXPLAIN SELECT * FROM staffs WHERE NAME = 'July'
EXPLAIN SELECT * FROM staffs WHERE LEFT(NAME,4) = 'July' --使用函数
EXPLAIN SELECT * FROM staffs WHERE NAME = '2000'
EXPLAIN SELECT * FROM staffs WHERE NAME = 2000 --使用类型转换

ここに画像の説明を挿入

スコープ後のすべての障害

範囲クエリを使用した後、範囲内のレコードが多すぎると、カスタムインデックスから主キーインデックスへのマッピングに時間がかかりすぎ、テーブル全体ほど高速ではないため、インデックスは無効になります。スキャン

提案:最後に範囲が指定されている可能性のあるフィールドのインデックス順を入力してください

ここに画像の説明を挿入

カバーインデックスより多くの使用

カバーインデックスを使用すると(インデックスを使用)、検索効率が向上します。インデックス列にのみアクセスするクエリ(インデックス列はクエリ列と同じです。select*は使用しないでください)

EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age = 23 and pos= 'dev'
EXPLAIN SELECT NAME,age,pos FROM staffs WHERE NAME = 'July' and age = 23 and pos= 'dev'

ここに画像の説明を挿入

不平等な使用は無効になります

等しくない(!=または<>)を使用すると、インデックスが無効になる場合があります

EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' 
EXPLAIN SELECT * FROM staffs WHERE NAME != 'July' 
EXPLAIN SELECT * FROM staffs WHERE NAME <> 'July' 

低バージョンのMySQLデータベースでは、次の場合にインデックスが失敗し、MySQL 8を使用しています。データベースの内部最適化が実行されます。インデックスは無効ではありませんが、タイプがrefからrangeに変わり、パフォーマンスは明らかに低下します。
ここに画像の説明を挿入

NULL値を使用する場合は注意してください

場合は許可フィールドが空である場合、

  • IS NULLは、インデックス障害を引き起こしません
  • IS NOT NULLを使用すると、インデックスが無効になります
    ここに画像の説明を挿入

ファジークエリプラス右

ワイルドカード%で始まるクエリのように、インデックスは失敗し、全表スキャンになります

EXPLAIN SELECT * FROM staffs WHERE NAME like '%July%' --左右都有通配符
EXPLAIN SELECT * FROM staffs WHERE NAME like '%July'  --模糊查询加左边
EXPLAIN SELECT * FROM staffs WHERE NAME like 'July%'  --模糊查询加右边

ここに画像の説明を挿入
問題:「%string%」のようなインデックス解決する方法が有効にならない:カバーインデックスを使用する(クエリフィールドはインデックスフィールドと可能な限り一致する必要があります)

一重引用符付きの文字列

EXPLAIN SELECT * FROM staffs WHERE NAME = '2000'
EXPLAIN SELECT * FROM staffs WHERE NAME = 2000 --使用类型转换

ここに画像の説明を挿入

使用または照会しないようにしてください

SELECT * FROM staffs WHERE NAME = 'July' OR NAME = 'z3'
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' OR NAME = 'z3'

タイプは使用後に範囲になりますまたは
ここに画像の説明を挿入

簡単な面接の質問

create table test03(
id int primary key not null auto_increment,
c1 char(10),
c2 char(10),
c3 char(10),
c4 char(10),
c5 char(10));

insert into test03(c1,c2,c3,c4,c5) values ('a1','a2','a3','a4','a5');
insert into test03(c1,c2,c3,c4,c5) values ('b1','b2','b3','b4','b5');
insert into test03(c1,c2,c3,c4,c5) values ('c1','c2','c3','c4','c5');
insert into test03(c1,c2,c3,c4,c5) values ('d1','d2','d3','d4','d5');
insert into test03(c1,c2,c3,c4,c5) values ('e1','e2','e3','e4','e5');

create index idx_test03_c1234 on test03(c1,c2,c3,c4);

実行計画分析

ケースA

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' 
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' 
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c3 = 'a3' 
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c3 = 'a3' and c4 = 'a4'

ここに画像の説明を挿入

ケースB

EXPLAIN SELECT * FROM test03 WHERE c4 = 'a4' and c3 = 'a3' and c2 = 'a2' and c1 = 'a1'  --MySQL内部优化,依然使用索引
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c4 = 'a4' and c3 > 'a3' 
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c4 = 'a4' ORDER BY c3 --c3用于排序
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c3 
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c4 --出现文件排序

ここに画像の説明を挿入

ケースC

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c5 = 'a5' ORDER BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c5 = 'a5' ORDER BY c3,c2
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c3,c2
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' ORDER BY c3,c2

ここに画像の説明を挿入

ケースD

私のデータベースは次のケースを実行できないため、SQLステートメントしかありません。スクリーンショットを確認していません。

EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c4 = 'a4' GROUP BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c4 = 'a4' GROUP BY c3,c2

ここに画像の説明を挿入

  • 命令は範囲です
  • Group byはグループ化であるため、最初に並べ替える必要があるため、一時テーブルが作成されます

ここに画像の説明を挿入


最適化式

完全な値は私のお気に入りと一致し、左端のプレフィックスを守る必要があります。
先頭の兄弟は死ぬことはできず、中間の兄弟は壊すことはできません。
インデックス列の計算が少なく、範囲が完全に無効です。
パーセントが右側に書き込まれるように、インデックスをカバーしても星は書き込まれません。
空を待機しません。値にもまたはがあります。インデックスの失敗にはlessを使用します
。VAR引用符が失われることはなく、高度なSQLは難しくありません。

おすすめ

転載: blog.csdn.net/single_0910/article/details/113860669