【Mysqlシリーズ】説明実行計画の「謎」について語る


mysqlデータベースを最適化するために話します。基本的な explain キーワードについて話し 、インデックスsqlデータベーステーブルを確立するかどうかを確認してから、sqlステートメントまたはインデックス最適化などについて説明し explain ます。この記事では主に理解について説明し ます。それは 理論 実践を 組み合わせて分割され ました。

理論パート

概念

まず、explain文法と関連する理論的知識を理解しましょう
構文
EXPLAIN SELECT select_options;

  1. select_optionsfrom where子句などを含む、selectステートメントのクエリオプションです
  2. このステートメントを実行すると、EXPLAINに続くselectステートメントの実行を分析でき、クエリテーブルのいくつかの特性を分析できます。
    例:EXPLAIN SELECT * FROMクラス;
    実行結果を図に示します。
    ここに写真の説明を挿入

実行計画の各列の具体的な意味は次のとおりです。

  • id:
查询的序号,包含一组数字,表示查询中执行select子句或操作表的顺序
1.id相同,执行顺序从上往下
2.id不同,id值越大,优先级越高,越先执行
  • select_type:
查询类型,主要用于区别普通查询,联合查询,子查询等的复杂查询
1.simple ——简单的select查询,查询中不包含子查询或者UNION
2.primary ——查询中若包含任何复杂的子部分,最外层查询被标记
3.subquery——在select或where列表中包含了子查询
4.derived——在from列表中包含的子查询被标记为derived(衍生),MySQL会递归执行这些子查询,把结果放到临时表中
5.union——如果第二个select出现在UNION之后,则被标记为UNION,如果union包含在from子句的子查询中,外层select被标记为derived,故在union中第二个及之后的select。
6.union result:UNION 临时表检索结果的select。
  • table:
输出的行所引用的表
  • partitions:
如果查询基于分区表,将会显示访问的是哪个区。
  • type:
显示连接类型,显示查询使用了何种类型,按照从最佳到最坏类型排序
1.system:表中仅有一行(=系统表)这是const联结类型的一个特例。
2.const:表示通过索引一次就找到,const用于比较primary key或者unique索引。因为只匹配一行数据,所以如果将主键置于where列表中,mysql能将该查询转换为一个常量
3.eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于唯一索引或者主键扫描,常用于连接查询。简单查询不会出现该类型
4.ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,是使用普通索引或者唯一性索引的部分前缀,它返回所有匹配某个单独值的行,可能会找多个符合条件的行,属于查找和扫描的混合体
5.range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是where语句中出现了between,in等范围的查询。这种范围扫描索引扫描比全表扫描要好,因为它开始于索引的某一个点,而结束另一个点,不用全表扫描
6.index:index 与all区别为index类型只遍历索引树。通常比all快,因为索引文件比数据文件小很多。
7.all:遍历全表以找到匹配的行
type常见类型从最优到最差:system > const > eq_ref > ref > range > index > ALL
注意:一般保证查询至少达到range级别,最好能达到ref。
  • possible_keys:
指出MySQL能使用哪个索引在该表中找到行
  • key:
显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。查询中如果使用覆盖索引,则该索引和查询的select字段重叠。
1.要想强制mysql使用或者忽视possible_key列中的索引,在查询中使用force index、use index或者ignore index。
  • key_len:
表示索引中使用的字节数,该列计算查询中使用的索引的长度在不损失精度的情况下,长度越短越好。如果键是NULL,则长度为NULL。该字段显示为索引字段的最大可能长度,并非实际使用长度。
  • ref:
显示索引的哪一列被使用了,如果有可能是一个常数,哪些列或常量被用于查询索引列上的值
  • rows:
根据表统计信息以及索引选用情况,大致估算出找到所需的记录所需要读取的行数
  • filtered:
指返回结果的行占需要读到的行(rows列的值)的百分比。
  • Extra:
包含不适合在其他列中显示,但是十分重要的额外信息
1、Using filesort:说明mysql会对数据适用一个外部的索引排序。而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成排序操作称为“文件排序”
2、Using temporary:使用了临时表保存中间结果,mysql在查询结果排序时使用临时表。常见于排序order by和分组查询group by。
3、Using index:表示相应的select操作用使用覆盖索引,避免访问了表的数据行。如果同时出现using where,表名索引被用来执行索引键值的查找;如果没有同时出现using where,表名索引用来读取数据而非执行查询动作。
4、Using where :表明使用where过滤
5、using join buffer:使用了连接缓存
6、impossible where:where子句的值总是false,不能用来获取任何元组
7、select tables optimized away:在没有group by子句的情况下,基于索引优化Min、max操作或者对于MyISAM存储引擎优化count(*),不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
8、distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作。

練習パート

use explain_detail;

DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `id` int(11) NOT NULL comment '教师id',
  `teacher_name` varchar(45) DEFAULT NULL comment '姓名',
  `teacher_no` varchar(45) DEFAULT NULL comment '教师编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO `teacher` (`id`, `teacher_name`, `teacher_no`)
VALUES (1,'溪源a','150921'), (2,'溪源b','201010'), (3,'溪源c','200325');
 
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `id` int(11) NOT NULL AUTO_INCREMENT comment '班级ID',
  `class_name` varchar(10) DEFAULT NULL comment '班级名称',
  PRIMARY KEY (`id`),
  KEY `idx_class_name` (`class_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO `class` (`id`, `class_name`)
VALUES (1,'java1'),(2,'java2'),(3,'java3');
 
# 班级教师关系表
DROP TABLE IF EXISTS `class_teacher`;
CREATE TABLE `class_teacher` (
  `id` int(11) NOT NULL,
  `class_id` int(11) NOT NULL comment '班级ID',
  `teacher_id` int(11) NOT NULL comment '教师ID'
  PRIMARY KEY (`id`),
  KEY `idx_class_teacher_id` (`class_id`,`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 # 插入数据
INSERT INTO `class_teacher` (`id`, `class_id`, `teacher_id`)
VALUES (1, 1, 1), (2, 1, 2), (3, 2, 1);

id

explain select (select id from teacher limit 1) from class;

ここに写真の説明を挿入

理論的な知識によると、id值越大执行优先级越高,id值相同则从上往下执行,id为null最后执行。図のID列から、ID = 2の最初の実行は最初に教師テーブルを照会することであることがわかります。

select_type

  1. 単純
    単純な選択クエリ。クエリにはサブクエリまたはUNIONが含まれていません
    ここに写真の説明を挿入

  2. プライマリおよびサブクエリ
    プライマリ:クエリに複雑なサブパーツが含まれている場合は、最も外側のクエリステートメントをマークます。
    サブクエリ:selectまたはwhereリストに含め子查询サブクエリステートメントをマークします。

explain select (select id from teacher) from class;

ここに写真の説明を挿入

サブクエリサブクエリ教師テーブル、外部選択がプライマリです。

ここに写真の説明を挿入
このSQLステートメントは、ID列に基づいてSQLステートメントの実行順序を区別できます。

  1. 派生サブクエリ含ま
    リストからは、としてマークされているderived(派生)、およびMySQLは再帰的にこれらのサブクエリを実行して結果を置く临时表に。
explain select * from (select * from teacher limit 1) tmp;

ここに写真の説明を挿入
ID = 2に従って、最初に教師テーブルにクエリを実行し、次に最も外側のクエリを実行して、結果を一時テーブルに保存します。

  1. union、union result
    union:2番目のselectがunionの後に表示される場合、それはunionとしてマークされます。unionがfrom句のサブクエリに含まれている場合、外側のselectは派生としてマークされます。したがって、unionの2番目のselectはそして、を選択します。
    ユニオン結果:ユニオン一時テーブルから結果を取得する場合に選択します。
explain select * from teacher where id = 1 union select * from teacher;

ここに写真の説明を挿入
id = 1がプライマリ、descriptionは外部クエリ、つまりこのSQLステートメントの前のステートメントを実行します
。id= 2はunionです。descriptionはunionの後のクエリステートメントです
。id= null、UNION RESULTとしてマークされ、生成された一時テーブルです。 ;
2つの結果は、選択検索のために結合結果にマージされます。
id列をもう一度説明します:1、2、null、実行順序2-> 1-> null。
最初にselect2を実行し、次に1を選択し、最後に実行して2つのCartesian製品からデータを取得します。

テーブル

出力行によって参照されるテーブル。

  1. from 子句中有子查询時間の場合、テーブルの列<derivenN>形式。現在のクエリID = N ** **依存クエリが表示されるため、最初のクエリ実行ID = Nになります。
    ここに写真の説明を挿入
  2. がある場合union、UNION RESULTテーブルの列<union1,2>1および2の値は、関与ユニオン選択行IDを示します。
    ここに写真の説明を挿入

タイプ

  1. null
    MySqlオプティマイザは、実行フェーズでテーブルやインデックスにアクセスしなくても、最適化フェーズでクエリステートメントを分解できます。
    ここに写真の説明を挿入

  2. システム

唯一のシステム・テーブル・データまたは衍生表<derived>のみデータがメイン・クエリに表示されはあまり意味がない、無視することができます。
ここに写真の説明を挿入

  1. const
    は、インデックスを介して1回検出されることを意味しますconst用于比较primary key 或者 unique索引(クエリタイプはインデックスタイプに関連しています)。ので、データの唯一の1行が一致する必要があり、すべてが高速です。主キーがwhereリストに配置されている場合、mysqlはクエリをconstに変換できます。
    ここに写真の説明を挿入
    whereステートメントの条件としてプライマリキーインデックスを使用します。

  2. eq_ref
    一意のインデックススキャン。インデックスキーごとに、テーブル内の1つのレコードのみが一致します。通常、プライマリキーまたは一意のインデックススキャンで使用されます。
    primarykey 或 unique keyインデックスのすべての部分が組み合わせて使用され、最大で1つの適格なレコードのみが返されます。これはconst以外の最良のタイプの接続である可能性があり、このタイプは単純なselectクエリには表示されません
    ここに写真の説明を挿入
    id列はすべて1です。id列の値が同じ場合、テーブルは上から下に実行されます。したがって、最初にclass_teacherテーブルを実行してから、クラステーブルを実行します。


  3. eq_refと比較すると、refは一意のインデックスを使用せず、代わりに通常のインデックスを使用します。または唯一性索引的部分前缀、インデックスを特定の値と比較すると、複数の修飾行が見つかる場合があります。
    ここに写真の説明を挿入

  4. レンジ
    用いてインデックス列は、指定された範囲は、範囲で取得する場合、クエリの背面(中間、>、 <、> =)。

ここに写真の説明を挿入

  1. インデックスすべてのインデックスのデータを
    クエリます只有索引树被扫描。インデックスファイルは通常データファイルよりも小さいため、通常はALLよりも高速です。
    ここに写真の説明を挿入

注:classテーブルの場合、class_nameインデックスは、テーブルが上で作成されたときに作成されます。同じクエリがteacherテーブルで使用され、テーブル全体がスキャンされます。

  1. すべての
    MySQLはテーブル全体をトラバースして、一致する行を見つけます。インデックスが確立されていないか、インデックスが無効である場合は、テーブル全体のデータを照会し、開発中にそれを回避するようにしてください。

ここに写真の説明を挿入

possible_keys

MySQLがテーブル内のレコードを検索するために使用できるインデックスを示します。クエリに関係するフィールドにインデックスがある場合、インデックスは一覧表示されますが、クエリでは使用されない場合があります(クエリで使用できるインデックス、インデックスがない場合はnullが表示されます)。 )
ここに写真の説明を挿入

キー

キー列には、MySQLが実際に使用することを決定したキー(インデックス)が表示されます。possible_keysに含める必要が
あります。インデックスが選択されていない場合、キーはNULLです。MySQLにpossible_keys列のインデックスを使用または無視させるには、クエリでFORCE INDEX、USE INDEX、またはIGNOREINDEXを使用します。
ここに写真の説明を挿入

key_len

使用されるインデックスを字节数表しである可能性があります(クエリで使用されるインデックスkey_lenに表示されるインデックスフィールドの可能な最大長値は、実際の長さではなく列によって計算されます。つまり、内部ではなく、key_len計算テーブルの定義に基づいて取得されます。取得)
不损失精确性的情况下,长度越短越好、長さが短いほど、インデックスの検証と照合の効率が高くなります。

以下のkey_lenの特定の値をそれぞれ使用普通索引して联合索引確認します
ここに写真の説明を挿入
プライマリキーインデックスを使用し、バイト数4を
ここに写真の説明を挿入
使用します。ジョイントインデックス、key_len = 8を使用します。

key_lenの計算ルールを拡張してみましょう。

1)字符串
char(n):n字节长度;
varchar(n)2字节存储字符串长度,如果是utf-8,则长度 3n + 22)数值类型
tinyint:1字节
smallint:2字节
int4字节
bigint:8字节  
3)时间类型
date:3字节
timestamp:4字节
datetime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL。(这是为什么会比正常计算多1的原因)。
索引最大长度是768字节,当字符串过长时,MySql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。


ref

キー列インデックスに表示されるテーブルルックアップ値で使用される列または定数は、通常、constまたはfieldnameです。
ここに写真の説明を挿入

結果セットの行数を見積もると、MySQLは、テーブル統計とインデックスの選択に基づいて、必要なレコードを見つけるために読み取る必要のある行数を見積もることを意味します。

フィルタリング

読み取る必要のある行に結果を返す行の割合を指します(行の列の値)。

ここに写真の説明を挿入
図から、rows = 3、指定されたデータ溪源aレコード数は1であることがわかります。したがって、フィルター処理された= 1/3 * 100/100 = 33.33%で、小数点以下2桁です。

ここに写真の説明を挿入
それでは、カバーするインデックス列をテーブル全体と比較する必要がないため、ここで1になるのはなぜですか。

エクストラ

この時点でようやく最後のコラムにたどり着きましたので、ちょっと待ってください〜

  1. インデックスの使用
    エクストラは、インデックスの使用を表示し、インデックスが使用されていることを示します。これは、高性能パフォーマンスです。通常、クエリに表示される列はインデックス列でカバーされます。
    ここに写真の説明を挿入

  2. whereExtraの使用whereの
    使用。これは、インデックスが使用されておらず、クエリ列がインデックス列でカバーされていないことを意味します。
    ここに写真の説明を挿入

  3. whereインデックスの使用
    Extraは、Whreの使用インデックスの使用を表示します。これは、クエリ列がインデックス列でカバーされ、whereフィルター条件がインデックス列の1つであるが、左端の原則の最初のインデックスではないことを意味します。これは、共同インデックスシナリオでよく見られます。
    ここに写真の説明を挿入

  4. NULL
    Extraは、クエリ列がインデックス列でカバーされていないことを示すnullを表示し、whereフィルタ条件がインデックスが使用されていることを示すインデックスの先頭列である
    が、一部のフィールドはインデックス列でカバーされていないことを示します。「テーブルに戻る」で実装する必要があるため、そうではありません。インデックスは純粋に使用され、完全に役に立たないわけではありません。

ここに写真の説明を挿入

  1. インデックス条件の使用
    Extraは、インデックス条件の使用がwhereの使用に類似していることを示しています。クエリ列はインデックス列で完全にカバーされておらず、where条件は先頭の列の範囲です。

ここに写真の説明を挿入

総括する

Xiyuanは、すべての人を助け、すべての人の支持を得ることを望んで、最終的にこの記事を完成させるために3泊を費やしました。何か問題があれば、大物が積極的に修正してくれることを願っています。

誰もがワンクリックトリプル接続を覚えてい
ます〜

おすすめ

転載: blog.csdn.net/xuan_lu/article/details/109210620