詳細に説明する
このテストで使用されるデータベースのバージョンは
、SQLステートメントを初期化するために5.7です。
CREATE TABLE `film` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `actor` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (1, 'a', '2017-12-02 15:27:18');
INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (2, 'b', '2017-12-22 15:27:18');
INSERT INTO `xnyh`.`actor`(`id`, `name`, `update_time`) VALUES (3, 'c', '2017-12-22 15:27:18');
INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (2, 'film 2');
INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (3, 'film0');
INSERT INTO `xnyh`.`film`(`id`, `name`) VALUES (1, 'film1');
CREATE TABLE `film_actor` (
`id` INT ( 11 ) NOT NULL,
`film_id` INT ( 11 ) NOT NULL,
`actor_id` INT ( 11 ) NOT NULL,
`remark` VARCHAR ( 255 ) DEFAULT NULL,
PRIMARY KEY ( `id` ),
KEY `idx_film_actor_id` (
`film_id`,
`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `film_actor` (`id`, `film_id`, `actor_id`) VALUES (1,1,1), (2,1,2),(3,2,1);
最初にexlpainステートメントを実行するEXPLAIN SELECT * from db
と、実行結果は次のように
なります。これらの12個のフィールドについて順番に説明します。
ID列
id列の値は、selectステートメントの実行順序を表し、selectに関連付けられています。id列の値が最初に実行されます。id列が空で最後に実行され、id列が同じ場合、上から下に順番に実行されます。
select_type列
クエリのタイプを表し、次の値があります。
シンプル:
サブクエリと結合キーワードは含まれていません
explain select * from film where id = 2;
プライマリ:
複雑なクエリ、unionステートメントの最も外側のselectステートメントまたは最も左のselectの場合、
explain select *,(select id from actor where id=1) from film
最も外側の検索はフィルムテーブルであるため、filmに対応するクエリタイプがプライマリです。
サブクエリ:
選択後のステートメントを除く、開始前の選択ステートメントのみ
explain select *,(select id from actor where id=1) from film
派生:
派生テーブル、selectステートメントがfrom句の後に含まれている場合、このタイプが生成され、中間結果が一時テーブルに格納されますが、5.7ではset session optimizer_switch='derived_merge=off';
、派生テーブルのマージを最適化するためにmysqlをオフにする必要があります。見てみましょう。閉じる前に、次のSQLシチュエーションを実行します。
explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;
クエリタイプが派生していないset session optimizer_switch='derived_merge=off'
ことがわかり、最適化をオフにして、派生クエリがあることを確認します。
連合:
組合での2回目以降の選択
explain select 1 union select 2 UNION select 3
テーブル列
テーブル列は、現在のselectステートメントによって照会されているテーブルを表します。
EXPLAIN SELECT id from actor UNION select id from film
最初の実行は、ユニオン後のクエリステートメントが現在フィルムテーブルにアクセスし、次にユニオンの左側のクエリステートメントが実行されます。現在のクエリはアクターテーブルであり、最後のクエリは依存するクエリ結果です。 1と2では、<union1,2>
代わりに使用してください。
タイプ列
タイプ列の値は次のとおりです:
NULL>システム> const> eq_ref> ref>範囲>インデックス> ALL;
実行効率は連続的に低下します。
ヌル:
代表的なクエリは、mysqlが最適化段階でクエリステートメントを分解できる場合に直接完了することができます。たとえば、テーブルやインデックスをクエリすることなく、徐々に最大または最小の列を取得できます。
EXPLAIN select min(id),max(id) from film
const:
whereが定数と正確に比較された後に主キーまたは一意のインデックスがある場合、mysqlはクエリを定数クエリに最適化し、次のSQLを実行します
explain select * from film where id = 2
。mysqlが内部でどのように最適化されている
explain EXTENDED select * from film where id = 2; show WARNINGS;
かを確認できます。mysqlが直接変換することがわかります。定数にそれをクエリを作成します
システム:
システムレベルに到達する場合は、次の条件を満たす必要があります。
1.システムテーブルまたは一時テーブルですか
2.テーブルにレコードが1つしかない
-
mysqlライブラリでproxies_privテーブルを見つけました。次のSQL実行を
explain select * from proxies_priv
確認できます。システムレベルに到達したことがわかります。 -
別の状況を見てみましょう。派生テーブル(一時テーブル)
explain extended select * from (select * from film where id = 1) tmp;
は、クエリタイプPRIMARYがシステムレベルに到達したことを確認できます。派生テーブル(一時テーブル)からクエリが実行され、派生テーブルには1つのレコードしかありません。システムレベルに到達することもできます。
eq_ref:
主キーまたは一意のインデックスが他のテーブルまたはフィールドに関連付けられている場合、1つのレコードのみが返されます。次のコード:
explain select * from film_actor left join film on film_actor.film_id = film.id;
idフィールドが一意であるため、フィルムテーブルにアクセスすると、タイプがeq_refレベルに達することがわかります。フィルムテーブル内にあるため、フィルムテーブルをクエリすると、idクエリに従って1つのレコードのみが関連付けられます。
参照:
eq_refと比較すると、refは通常のインデックスまたはジョイントインデックスのプレフィックス一致である必要があります。
-
通常のインデックスクエリ
explain select * from film where name = 'film1';
-
ジョイントインデックスプレフィックスマッチング
explain select film_id from film left join film_actor on film.id = film_actor.film_id;
範囲:
範囲インデックスは、通常、> <> =このような比較演算子で、範囲レベルに到達します
explain select * from actor where id > 1;
インデックス
テーブルインデックス全体をスキャンします。クエリ列はインデックスを作成しましたが、インデックスフィールドに従ってフィルタリングされていません(インデックスを無効にする操作を除く)
explain select * from film
すべて
テーブル全体をスキャンします。通常、インデックスは作成されず、インデックスの最適化を追加する必要があります
explain select * from actor;
possible_keys
この列は、クエリが検索に使用できるインデックスを示します。説明すると、possible_keysに列がある場合がありますが、キーにNULLが表示されます。この状況は、テーブルにデータがあまりないためです。MySQLは、インデックスがこのクエリにあまり役立たないと考え、テーブル全体のクエリを選択します。列がNULLの場合、関連するインデックスはありません。この場合、where句をチェックして、クエリのパフォーマンスを向上させるために適切なインデックスを作成できるかどうかを確認してから、explainを使用して効果を確認できます。
キー
この列は、MySQLがテーブルへのアクセスを最適化するために実際に使用するインデックスを示しています。インデックスが使用されていない場合、列はNULLです。mysqlにpossible_keys列のインデックスを使用または無視するように強制する場合は、クエリでインデックスを強制し、インデックスを無視します。
key_len
この列は、使用されたインデックスの長さを記録し、通常、ジョイントインデックスが完全に有効であるかどうかを判断するために使用されます。値は、さまざまなデータ型に従って計算されます。
key_lenの計算ルールは次のとおりです。
- ストリング
- char(n):長さnバイト
- varchar(n):2バイトのストレージ文字列の長さ。utf-8の場合、長さは3n +2です。
- 数値型
- tinyint:1バイト
- smallint:2バイト
- int:4バイト
- bigint:8バイト
- 時間タイプ
- 日付:3バイト
- タイムスタンプ:4バイト
- 日時:8バイト
フィールドをNULLにできる場合は、NULLかどうかを記録するために1バイトのレコードが必要です。インデックスの最大長は768バイトです。文字列が長すぎる場合、mysqlは左側のプレフィックスと同様のプロセスを実行します。インデックスを作成し、インデックスを作成するために文字の前半を抽出します。
テーブルfilm_actorを作成するときに、ジョイントインデックスを作成しました
KEY `idx_film_actor_id` (`film_id`,`actor_id`)
この共同指数を計算に使用します
- ジョイントインデックスの最初のフィールドのみを使用し
explain select * from film_actor where film_id = 2;
ます。key_lenが4であることがわかります。ジョイントインデックスフィールドの最初のフィールドに従ってフィルタリングします。上記の計算方法と組み合わせて、film_idフィールドのintタイプを見てみましょう。 file_idをNULLにすることはできません。その場合、key_lenは4です。
- ジョイントインデックスの2つのフィールドを使用
explain select * from film_actor where film_id = 2 and actor_id = 3
します。結果は8であることがわかります。これは、これら2つのフィールドがint型であり、NUllではないため、インデックスの全長が8であり、インデックスが完全に有効であることを意味します。
ref
この列には、キー列レコードのインデックスのテーブルルックアップ値で使用される列または定数が表示されます。一般的なものは、const(定数)、フィールド名(例:film.id)です。
行
この列は、MySQLが読み取りおよび検出すると推定する行数です。これは、結果セットの行数ではないことに注意してください。
追加の列
この表示インデックスの追加情報、メインフィールド情報は次のとおりです。
-
インデックス
クエリフィールドの使用はインデックスでカバーされています
explain select film_id from film_actor
-
where
whereを使用する背後にあるフィールドは、インデックスの作成、方法の最適化、インデックスの作成に使用されません。
explain select film_id from film_actor where remark = '描述';
-
インデックス条件を使用する
クエリでは、where条件は先頭の列の範囲です。
explain select * from film_actor where film_id = 1 and actor_id >3;
-
一時テーブルを使用して一時テーブルを作成する場合、この状況を最適化する必要があるため、mysqlクエリプロセスはクエリを支援するために一時テーブルを作成する必要があります。
explain select distinct name from actor;
重複排除されたフィールドにインデックスを追加することで、最適化効果を実現できます。
CREATE index idx_name on actor(name)
後続のテストを容易にするには、新しく作成されたインデックスを削除する必要があります。DROP INDEX idx_name on actor
-
filesort
を使用する場合、データはインデックスソートなしでソートされます。データ量が少ない場合はメモリでソートされ、データ量が多い場合はディスク上でソートされます。通常、インデックスの最適化が必要です。ソートフィールドはインデックス付けされていません。
explain select * from actor order by name;
次の並べ替えフィールドはインデックスを作成するため、インデックスで並べ替えられます
explain select * from film order by name;
-
最適化されたテーブルの選択
は、集計関数を使用してインデックス付きフィールドをクエリします
explain select max(id) from actor
Wechatで検索を検索[LeZaiオープントーク]ハンサムな私をフォローし、[乾物を受け取る]と返信すると、Javaの基本、Javaの同時実行など、選択を待っているインタビュー資料や建築家の必読の本がたくさんあります。マイクロサービス、ミドルウェアなど。より多くの情報があなたを待っています。