九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
MySQL的執(zhí)行計劃和索引詳解

使用explain關鍵字可以模擬優(yōu)化器執(zhí)行sql語句,從而知道m(xù)ysql是如何處理sql語句的,分析你的查詢語句或者是結構性能。

我們通過幾張表來使用explain的例子:

在select語句之前增加explain關鍵字,MySQL會在查詢的基礎上設置一個標記,執(zhí)行查詢時,會返回執(zhí)行計劃的信息,而不是執(zhí)行這條sql語句(如果from中包含子查詢,仍會執(zhí)行該子查詢的,將結果放入臨時表中)

使用的的表

1.actor表(不設置索引,存儲引擎是InnoDB)

2.film表(設置name索引(輔助索引),存儲引擎是InnoDB)

3.film-actor表(設置聯(lián)合輔助索引(film_id,actor_id))

使用的表我們建立完畢了,那接下來就讓我們熟悉一下explain的始終和返回執(zhí)行計劃中字段的含義

mysql>EXPLAIN SELECT  (SELECT  1 from actor ) from film;

在查詢中的每一個表會輸出一行,如果有兩個表通過join連接查詢,那么會輸出兩行,表的意思相當廣泛:可以是子查詢,一個union結果等。

explain有兩個輔助寫法:

1)explain extended:會在explain的基礎上額外提供一些查詢的優(yōu)化的信息,緊隨其后的通過show warnings 命令可以的到優(yōu)化后的查詢語句,從而看出優(yōu)化器優(yōu)化了什么,二外有filtered列,是一個半分比的值,rows*filtered/100可以估算出來將要和explain中前一個表進行連接的行數(shù)(前一個表指的是explain中的id值比當前id值小的表)

mysql>EXPLAIN EXTENDED SELECT * from film where id = 1;

mysql>show WARNINGS;(Note 得到優(yōu)化后的語句)

2)explain partitions :相比explain多了個partition字段,如果查詢是基于分表的的話,會顯示查詢將訪問的分區(qū)

那接下來我們介紹一下explain中每個列的信息

1.id列

id列的編號是select的序列號,有幾個select就有幾個id,并且id的順序是按select出現(xiàn)的順序增長的。MySQL將 select查詢分為簡單查詢(SIMPLE)和復雜查詢(PRIMARY)。

復雜查詢分為三類:簡單子查詢、派生表(from語句中的子查詢) 、union查詢。

id列越大執(zhí)行優(yōu)先級越高,id相同則從上往下執(zhí)行,id為NULL最后執(zhí)行1)簡單子查詢

1)簡單子查詢

mysql>EXPLAIN SELECT (SELECT 1 FROM actor LIMIT 1) FROM film;

2)from字句中的子查詢(在mysql5.7的版中沒有派生表的返回,具體原因不明,可能是5.7的優(yōu)化了)

mysql>EXPLAIN SELECT id FROM (SELECT id FROM film) f;

這個查詢執(zhí)行時有個臨時表別名為f,外部的select查詢就是引用了這個臨時表

3)union查詢

mysql>EXPLAIN select 1 from film union all select 1 from actor;

union 結果總是放在一個匿名的臨時表中,臨時表不在sql中出現(xiàn),因此他的id是null

2.select_type列

select_type表示對應行是簡單的還是復雜的查詢,如果是復雜的查詢,又是上述三種哪一種

1)simple:簡單查詢,查詢不包含子查詢和union

mysql>explain select * from film where id =1;

2)primary:復雜查詢中的最外層select

3)subquery:包含select中的子查詢(不在from子句中)

4)derived:包含在from子句中的子查詢,mysql會將結果存放在一個臨時表中,也稱派生表(derived的英文義)

用這個例子來解析primary,subquery,derived類型

mysql>explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;

5)union :在union中的第二和隨后的select

6)union result:從union臨時表檢索結果的select

用這個例子來了解union和union result 類型:

mysql> explain select 1 from film union select 1 from film ;

3.table 列

這一列表示explain的一行正在訪問哪個表。

當from子句中有子查詢的時候,table列是<derivenN>格式,表示當前查詢依賴id=N的查詢,于是先執(zhí)行id=N的查詢。

當有union時,union result的table列的值為<union1,2>,1和2表示參與的select行id

4.type列

這一列表示關聯(lián)類型和訪問類型,即MySQL決定如何查找表中的行,查找的數(shù)據(jù)記錄的大概范圍。

依次從最優(yōu)到最差分別為:system>const>eq_ref>ref>range>index>all(常用的)

一般來說,得到保證查詢打到range級別,最好打到ref級別

NULL:MySQL能夠在優(yōu)化階段分解查詢語句,在執(zhí)行階段用不著再訪問表或索引。例如再索引列中選區(qū)最小值,可以單獨擦查找索引來完成,不需要再執(zhí)行時訪問表。

mysql>explain select min(id) from film;

注意:mysql中主鍵就是索引,mysql會幫主鍵主動建立索引的

const,system:mysql能對查詢的某部分進行優(yōu)化并將其轉化成一個常量(可以看著show warnings的結果)。用于primary_key和union key的所有列和常數(shù)比較的時候,所以表最多一個匹配行,讀一次,速度比較快,system時const的特例,表中只有一條元組數(shù)據(jù)匹配就是system

mysql>explain extended select * from (select * from film where id = 1) f; 

注意:const就是查詢條件時主鍵或者唯一性約束的,查詢出來的就只有一條數(shù)據(jù)的,而system查詢的表就只有一條數(shù)據(jù)的。

mysql>show warnings;(優(yōu)化后的sql)

eq_ref:primary_key或者union key索引的所有部分被連接使用,最多返回一條符合條件的記錄,這可能再const之外最好的連接類型了,簡單的select查詢就不會出現(xiàn)這種類型

mysql>explain select * from film_actor left join film on film_id = film.id ;

注意:film_actor也是使用索引查詢的原因時覆蓋索引(后面有說)

ref相比eq. ret,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前綴,索引要和某個值相比較,可能會找到多個符合條件的行。
1.簡單select查詢,name是普通索引(非唯一索引)

mysql>explain select * from film where name = "film1";

2.關聯(lián)表查詢,idx_ film_ actor_ id是film_ 1d和actor_ id的聯(lián)合索引,這里使用到了film_ actor的左邊前綴film_id部分。

mysql> explain select * from film LEFT JOIN film_actor on film.id = film_actor.film_id;

 

range:范圍掃描通常出現(xiàn)在in(), between,> <, >=等操作中。使用一個索引來檢索給定范圍的行。

mysql>explain select *  from actor WHERE id > 1

index:掃描全表索引,這通常比all快一些,(index是從索引中讀取的,而all是從硬盤中讀?。?/p>

mysql>explain select * from film ;

ALL:即全表掃描,意味著mysql需要從頭到尾去查詢所需要的好行,通常情況下這需要增加索引來進行優(yōu)化

mysql>explain select * from actor;

5.possible_keys列

這一列顯示查詢可能使用哪些索引來查找。

explain時可能出現(xiàn)posible. keys有列,而key顯示NULL的情況,這種情況是因為表中數(shù)據(jù)不多, mysq認為索引對此查詢幫助不大,選擇了全表查詢。

如果該列是NULL,則沒有相關的素引,在這種情況下,可以通過檢查where子句看是否可以創(chuàng)造一個適當?shù)乃饕齺硖岣卟樵冃阅?,然后用explain查看效果。

6.key列

這一列是示mysq實際采用索引來優(yōu)化対該表的訪問
如果沒有使用索引,則垓列是NULL.如果想強制mysq使用或忽視possible. keys列中的索引,在査洵中使用force index. ignore index。

7.key_len列

這一列顯示了mysql在索引里使用的字節(jié)數(shù),通過這個值可以算出具體使用了索引中的哪些列。 

舉例來說,film_actor的聯(lián)合索引 idx_film_actor_id 由 film_id 和 actor_id 兩個int列組成,并且每個int是4字節(jié)。通過結果中的key_len=4可推斷出查詢使用了第一個列:film_id列來執(zhí)行索引查找。

mysql>explain select * from film_actor where film_id = 2;

key_len計算規(guī)則如下

字符串

char(n):n字節(jié)長度

varchar(n):2字節(jié)存儲字符串長度,如果是utf-8,則長度 3n + 2

數(shù)值類型

tinyint:1字節(jié)

smallint:2字節(jié)

int:4字節(jié)

bigint:8字節(jié)  

時間類型 

date:3字節(jié)

timestamp:4字節(jié)

datetime:8字節(jié)

如果字段允許為 NULL,需要1字節(jié)記錄是否為 NULL

索引最大長度是768字節(jié),當字符串過長時,mysql會做一個類似左前綴索引的處理,將前半部分的字符提取出來做索引。

 

8. ref列
這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有: const (常量) ,字段名(例: film.id)
9. rows列
這一列是mysq估計要讀取并檢測的行數(shù),注意這個不是結果集里的行數(shù)。

 

10. Extra列
這一列展示的是額外信息。常見的重要值如下:
Using index: 查詢的列被索引覆蓋,并且where篩選條件是索引的前導列,是性能高的表現(xiàn)。一般是使用了覆蓋索引索引包含了所有查詢的字段)。對于innodb來說,如果是輔助索引性能會有不少提高.

mysql>explain select film_id from film_actor where film_id = 1;

Using where : 查詢的列未被索引覆蓋 where篩選條件非索引的前導列

mysql>explain select * from actor where name = 'a';

 

Using where Using index: 查詢的列被索引覆蓋,并且where篩選條件是索引列之一但是不是索引的前導列,意味著無法直接通過索引查找來查詢到符合條件的數(shù)據(jù)
mysql> explain select film_id from film_actor where actor_id = 1;

 

NULL:查詢的列未被索引覆蓋,并且where篩選條件是索引的前導列,意味著用到了索引,但是部分字段未被索引覆蓋,必須通過“回表“來實現(xiàn),不是純粹地用到了索引,也不是完全沒用到索引.

 

Using temporary: mysql需要創(chuàng)建一張臨時表來處理査洵. 出現(xiàn)這種情況一般是要迸行優(yōu)化的, 首先是想到用索引來優(yōu)化.

1. actor.name沒有索引,此時創(chuàng)建了張臨時表來dstinct.

mysql>explain select distinct name from actor;

2.film.name 建立了idx_name索引,此時查詢時extra時using index,沒有使用臨時表

mysql>explain select distinct name from film;

    Using filesort: mysql會對結果使用一個外部索引排序,而不是按索引次序從表里讀取行。此時mysql會根據(jù)連接類型瀏覽所有符合條件的記錄,井保存排序關鍵字和指針,然后排序關鍵字并按順序檢索行信息。這種情況下一般也是要考慮使用索引來優(yōu)化的。

1. actor .name未創(chuàng)建索引,會瀏覽actor整個表, 保存排序關鍵字name和對那個的id,然后排序name并檢索記錄

mysql>explain select * from actor order by name;

2.film.name 建立了idx_name索引,此時查詢時extra時using index

索引最佳實踐

使用的表

  1. CREATE TABLE `employees` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
  4. `age` int(11) NOT NULL DEFAULT '0' COMMENT '年齡',
  5. `position` varchar(20) NOT NULL DEFAULT '' COMMENT '職位',
  6. `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間',
  7. PRIMARY KEY (`id`),
  8. KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
  9. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='員工記錄表';
  10. INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW());
  11. INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW());
  12. INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());

 最佳實踐

1. 全值匹配

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22;

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';

2.最佳左前綴法則

 如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始并且不跳過索引中的列。

EXPLAIN SELECT * FROM employees WHERE age = 22 AND position ='manager';

EXPLAIN SELECT * FROM employees WHERE position = 'manager';

EXPLAIN SELECT * FROM employees WHERE name = 'LiLei';

3.不在索引列上做任何操作(計算、函數(shù)、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描

EXPLAIN SELECT * FROM employees WHERE name = 'LiLei';

EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'LiLei';

 4.存儲引擎不能使用索引中范圍條件右邊的列

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager';

5.盡量使用覆蓋索引(只訪問索引的查詢(索引列包含查詢列)),減少select *語句

EXPLAIN SELECT name,age FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';

6.mysql在使用不等于(!=或者<>)的時候無法使用索引會導致全表掃描

EXPLAIN SELECT * FROM employees WHERE name != 'LiLei'

7.is null,is not null 也無法使用索引

EXPLAIN SELECT * FROM employees WHERE name is null

8.like以通配符開頭('$abc...')mysql索引失效會變成全表掃描操作

EXPLAIN SELECT * FROM employees WHERE name like '%Lei'

EXPLAIN SELECT * FROM employees WHERE name like 'Lei%'

問題:解決like'%字符串%'索引不被使用的方法?

a)使用覆蓋索引,查詢字段必須是建立覆蓋索引字段

EXPLAIN SELECT name,age,position FROM employees WHERE name like '%Lei%';

b)當覆蓋索引指向的字段是varchar(380)及380以上的字段時,覆蓋索引會失效!

9.字符串不加單引號索引失效

EXPLAIN SELECT * FROM employees WHERE name = '1000';

EXPLAIN SELECT * FROM employees WHERE name = 1000;

10.少用or,用它連接時很多情況下索引會失效

EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' or name = 'HanMeimei';

總結:

like KK%相當于=常量,%KK和%KK% 相當于范圍

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
mysql總結之explain
MySQL explain詳解
[慢查優(yōu)化]慎用MySQL子查詢,尤其是看到DEPENDENT SUBQUERY標記時
MYSQL語句調優(yōu):MYSQL Explain 執(zhí)行計劃輸出詳解
深入解析:從源碼窺探MySQL優(yōu)化器
?MySQL的 select 和 sort 變量
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服