轉(zhuǎn)載自:聯(lián)合索引優(yōu)化多條件查詢
聯(lián)合索引是由多個字段組成的組合索引拴袭。若經(jīng)常需要使用多個字段的多條件查詢(WHERE col1 = … AND col2 = … AND col3 = …),可以考慮使用聯(lián)合索引。
現(xiàn)在數(shù)據(jù)表myIndex中i_testID是主鍵列谒养,其他列無任何索引:
多條件查找名字為xiaoming也物,城市為beijing逛漫,年齡為21的人:
返回了一行數(shù)據(jù)垛膝,從執(zhí)行計劃中看到,查詢沒有使用任何索引第股,進行了全表掃描应民,磁盤IO大。
為vc_Name建立索引:
進行同樣的查詢并查看執(zhí)行計劃:
返回了相同的結(jié)果夕吻,分析執(zhí)行計劃:SQL通過剛剛建立的index_of_name索引诲锹,不再進行全表掃描,而是先在索引中查找滿足節(jié)點值為xiaoming的節(jié)點(有5個)涉馅,再指向數(shù)據(jù)庫中相應的行归园,返回一個初步結(jié)果集后再由另外兩個條件進行一步步篩選得到最終結(jié)果。大大減少了磁盤IO稚矿,查詢效率也高于前者庸诱。
雖然在 vc_Name 上建立了索引捻浦,查詢時MYSQL不用掃描整張表,效率有所提高桥爽,但離我們的要求還有一定的距離朱灿。同樣的,在 vc_City 和 i_Age 分別建立的MySQL單列索引的效率相似钠四。為了進一步榨取 MySQL 的效率盗扒,就要考慮建立組合索引。
為多條件涉及的列建立聯(lián)合索引:
值得注意的是缀去,建立索引的時候應該根據(jù)需要規(guī)定索引長度侣灶,例如一個人的名字長度應該不會超過10個字符,通過vc_Name(10)規(guī)定索引長度后一定長度可以減少索引所占內(nèi)存缕碎。
現(xiàn)在表中的結(jié)構(gòu):
進行相同的查詢并查看執(zhí)行計劃:
返回相同的結(jié)果褥影,從執(zhí)行計劃可以看到:本次查詢使用了聯(lián)合索引name_city_age,在遍歷索引時就確定了只有一個節(jié)點滿足條件阎曹,直接指向數(shù)據(jù)庫表進行查詢(rows:1)伪阶。有更少的磁盤IO,所用時間更少处嫌!
使用聯(lián)合索引應該注意:
- MySQL使用聯(lián)合索引只能使用左側(cè)的部分,例如INDEX(a,b,c)斟湃,當條件為a或a,b或a,b,c時都可以使用索引熏迹,但是當條件為b,c時將不會使用索引。這好比一本先根據(jù)姓凝赛,再根據(jù)名進行排序的電話簿注暗,當查找的時候有姓的條件,效率會比沒有任何條件高墓猎;如果在姓的基礎上還有名的條件捆昏,效率會更高;但若只有名的條件毙沾,電話簿將不起作用骗卜。
- 離散度更高的索引應該放在聯(lián)合索引的前面,因為離散度高索引的可選擇性高左胞】懿郑考慮一種極端的情況,數(shù)據(jù)表中有100條記錄烤宙,若INDEX(a,b)中a只有兩種情況遍烦,而b有100種情況。這樣對于查詢唯一記錄a = …躺枕,b = …時服猪,先遍歷全部索引看滿足a條件的有50個索引節(jié)點供填,接下來還要再一個個遍歷這50個索引節(jié)點。如果是INDEX(b,a)罢猪,先遍歷全部索引發(fā)現(xiàn)滿足b條件的索引節(jié)點只有一個捕虽,再遍歷這個節(jié)點發(fā)現(xiàn)也滿足a條件。雖然最后都能找到那個唯一的索引節(jié)點坡脐,但是第二種索引順序?qū)σ姹闅v索引效率有很大的提高(用電話薄的思想去思考問題)泄私。
- 查看列的離散程度:
customer_id列的離散程度更高,建聯(lián)合索引時應該INDEX(customer_id,staff_id);