聯(lián)合索引和單個(gè)索引選擇
## 一個(gè)字段不重復(fù)的總量與數(shù)據(jù)總量的比值,越大選擇性越好。
SELECT count(DISTINCT(key))/count(*) AS Selectivity FROM table;
## 舉例如下截取last_name前4個(gè)字符
ALTER TABLE employees.employees
ADD INDEX `first_name_last_name4` (first_name, last_name(4));
SELECT count(DISTINCT(concat(first_name, left(last_name, 4))))/count(*) AS Selectivity FROM employees.employees;
對(duì)比,值越大越好
強(qiáng)制使用某個(gè)索引
...
FROM table_name1 a USE INDEX (index_name1) LEFT JOIN table_name2 c
FORCE INDEX FOR JOIN (index_name2)
...
使用explain分析索引
1、id:SQL執(zhí)行的順序的標(biāo)識(shí)。
sql從里向外執(zhí)行,sql是按照id從大到小執(zhí)行的。
2、select_type: select類(lèi)型
1)、SIMPLE(不使用UNION或子查詢(xún)等)
- 、PRIMARY:最外層的select
3)、DERIVED:派生表的SELECT(FROM子句的子查詢(xún))
4)、UNION:UNION中的第二個(gè)或后面的SELECT語(yǔ)句
5)、UNION RESULT:UNION的結(jié)果。
6)、DEPENDENT UNION:UNION中的第二個(gè)或后面的SELECT語(yǔ)句,取決于外面的查詢(xún)
7)、SUBQUERY:子查詢(xún)中的第一個(gè)SELECT
8)、DEPENDENT SUBQUERY:子查詢(xún)中的第一個(gè)SELECT,取決于外面的查詢(xún)
3、table:表的名字。
有時(shí)不是真實(shí)的表名字,看到的是derivedx(x是個(gè)數(shù)字,我的理解是第幾步執(zhí)行的結(jié)果)
4、type:連接操作的類(lèi)型。
這列很重要,顯示了連接使用了哪種類(lèi)別,有無(wú)使用索引。在各種類(lèi)型的關(guān)聯(lián)關(guān)系當(dāng)中,效率最高的是system,然后依次是const、eq_ref、ref、range、index和 All。一般來(lái)說(shuō),得保證查詢(xún)至少達(dá)到range級(jí)別,最好能達(dá)到ref,否則就可能會(huì)出現(xiàn)性能問(wèn)題。
1)、system
表只有一行:system表。這是const連接類(lèi)型的特殊情況
2)、const
表中的一個(gè)記錄的最大值能夠匹配這個(gè)查詢(xún)(索引可以是主鍵或惟一索引)。因?yàn)橹挥幸恍校@個(gè)值實(shí)際就是常數(shù),因?yàn)镸YSQL先讀這個(gè)值然后把它當(dāng)做常數(shù)來(lái)對(duì)待
3)、eq_ref
在連接中,MYSQL在查詢(xún)時(shí),從前面的表中,對(duì)每一個(gè)記錄的聯(lián)合都從表中讀取一個(gè)記錄,它在查詢(xún)使用了索引為主鍵或惟一鍵的全部時(shí)使用
4)、ref
這個(gè)連接類(lèi)型只有在查詢(xún)使用了不是惟一或主鍵的鍵或者是這些類(lèi)型的部分(比如,利用最左邊前綴)時(shí)發(fā)生。對(duì)于之前的表的每一個(gè)行聯(lián)合,全部記錄都將從表中讀出。這個(gè)類(lèi)型嚴(yán)重依賴(lài)于根據(jù)索引匹配的記錄多少(越少越好)
5)、range
這個(gè)連接類(lèi)型使用索引返回一個(gè)范圍中的行,比如使用>或<查找東西時(shí)發(fā)生的情況
6)、index
這個(gè)連接類(lèi)型對(duì)前面的表中的每一個(gè)記錄聯(lián)合進(jìn)行完全掃描(比ALL更好,因?yàn)樗饕话阈∮诒頂?shù)據(jù))
7)、ALL
這個(gè)連接類(lèi)型對(duì)于前面的每一個(gè)記錄聯(lián)合進(jìn)行完全掃描,這一般比較糟糕,應(yīng)該盡量避免。因?yàn)樗獟呙枵麄€(gè)表。你可以加入更多的索引來(lái)解決這個(gè)問(wèn)題。
5、possible_key:MySQL在搜索數(shù)據(jù)記錄時(shí)可以選用的各個(gè)索引名。
這里的索引名是創(chuàng)建索引時(shí)指定的索引昵稱(chēng);如果索引沒(méi)有昵稱(chēng),則默認(rèn)顯示的是索引中第一個(gè)列的名字(在上一節(jié)舉的例子中是“firstname”)。默認(rèn)索引名字的含義往往不是很明顯。
6、key:它顯示了MySQL實(shí)際使用的索引。
key數(shù)據(jù)列是MySQL實(shí)際選用的索引,如果它為空(或NULL),則MySQL不使用索引。
7、key_len:索引中被使用部分的長(zhǎng)度,以字節(jié)計(jì)。
key_len的值可以告訴你在聯(lián)合索引中mysql會(huì)真正使用了哪些索引。 在上例中,key_len是102,其中firstname占50字節(jié),lastname占50字節(jié),age占2字節(jié)(smallint存儲(chǔ)大小為2字節(jié))。如果MySQL只使用索引中的firstname部分,則key_len將是50。 在不損失精確性的情況下 ,key_len數(shù)據(jù)列里的值越小越好(意思是更快)。
8、ref:顯示使用哪個(gè)列或常數(shù)與key一起從表中選擇行。
ref數(shù)據(jù)列給出了關(guān)聯(lián)關(guān)系中另一個(gè)數(shù)據(jù)表里的數(shù)據(jù)列的名字。
9、rows:MySQL所認(rèn)為的它在找到正確的結(jié)果之前必須掃描的記錄數(shù)。
顯然,這里最理想的數(shù)字就是1。
10、extra:附加信息
Using index和Using where會(huì)遇到的比較多,可以重點(diǎn)記下,其他的我沒(méi)怎么遇到過(guò)了解即可,遇到具體問(wèn)題可以查閱哈
1)、Distinct
一旦MYSQL找到了與行相聯(lián)合匹配的行,就不再搜索了
2)、Not exists
MYSQL優(yōu)化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標(biāo)準(zhǔn)的行,就不再搜索了 。
3)、Range checked for each
沒(méi)有找到理想的索引,因此對(duì)于從前面表中來(lái)的每一個(gè)行組合,MYSQL檢查使用哪個(gè)索引,并用它來(lái)從表中返回行。這是使用索引的最慢的連接之一
4)、Using filesort
看到這個(gè)的時(shí)候,查詢(xún)就需要優(yōu)化了。MYSQL需要進(jìn)行額外的步驟來(lái)發(fā)現(xiàn)如何對(duì)返回的行排序。它根據(jù)連接類(lèi)型以及存儲(chǔ)排序鍵值和匹配條件的全部行的行指針來(lái)排序全部行
5)Using index
列數(shù)據(jù)是從僅僅使用了索引中的信息而沒(méi)有讀取實(shí)際的行動(dòng)的表返回的,這發(fā)生在對(duì)表的全部的請(qǐng)求列都是同一個(gè)索引的部分的時(shí)候
6)Using temporary
看到這個(gè)的時(shí)候,查詢(xún)需要優(yōu)化了。這里,MYSQL需要?jiǎng)?chuàng)建一個(gè)臨時(shí)表來(lái)存儲(chǔ)結(jié)果,這通常發(fā)生在對(duì)不同的列集進(jìn)行ORDER BY上,而不是GROUP BY上
7)Using where
使用了WHERE從句來(lái)限制哪些行將與下一張表匹配或者是返回給用戶(hù)。如果不想返回表中的全部行,并且連接類(lèi)型ALL或index,這就會(huì)發(fā)生,或者是查詢(xún)有問(wèn)題