一文弄懂MySQL索引創(chuàng)建原則
一、適合創(chuàng)建索引
1、字段的數(shù)值有唯一性限制
根據(jù)Alibaba規(guī)范,指明在業(yè)務(wù)上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。
例如,學(xué)生表中的學(xué)號(hào)時(shí)具有唯一性的字段,為該字段建立唯一性索引可以快速查詢出某個(gè)學(xué)生的信息,如果使用姓名的話,可能存在同名的情況,從而降低查詢速度。
2、頻繁作為Where查詢條件的字段
某個(gè)字段在Select語句的Where條件中經(jīng)常被使用到,那么就需要給這個(gè)字段創(chuàng)建索引,尤其實(shí)在數(shù)據(jù)量大的情況下,創(chuàng)建普通索引就可以大幅提升查詢效率。
比如測(cè)試表student_info有100萬數(shù)據(jù),假設(shè)查詢student_id=112322的用戶信息,如果沒有對(duì)student_id字段創(chuàng)建索引,查詢結(jié)果如下:
select course_id, class_id, name, create_time,student_id from student_info where student_id = 112322;# 花費(fèi)211ms
為student_id創(chuàng)建索引后,查詢結(jié)果如下:
alter table student_info add index idx_sid(student_id); select course_id, class_id, name, create_time,student_id from student_info where student_id = 112322;# 花費(fèi)3ms
3、經(jīng)常Group by和Order by的列
索引就是讓數(shù)據(jù)按照某種順序進(jìn)行存儲(chǔ)或檢索,因此當(dāng)使用Group by對(duì)數(shù)據(jù)進(jìn)行分組查詢或使用Order by對(duì)數(shù)據(jù)進(jìn)行排序的時(shí)候 ,就需要對(duì)分組或排序的字段進(jìn)行索引。如果待排序的列有多個(gè),那可以在這些列上建立組合索引。
比如,按照student_id對(duì)學(xué)生選秀的課程進(jìn)行分組,顯示不同的student_id和課程的數(shù)量,顯示100條。如果不對(duì)student_id創(chuàng)建索引,查詢結(jié)果如下:
select student_id,count(*) as num from student_info group by student_id limit 100;#花費(fèi)2.466s
為student_id創(chuàng)建索引后,查詢結(jié)果如下:
alter table student_info add index idx_sid(student_id); select student_id,count(*) as num from student_info group by student_id limit 100;#花費(fèi)6ms
對(duì)于既有g(shù)roup by又有order by的查詢語句,建議最好建立聯(lián)合索引,并且將group by中的字段放到order by字段的前邊,滿足‘最左前綴匹配原則’,這樣索引的利用率就會(huì)高,自然查詢的效率也就會(huì)高;同時(shí)8.0之后的版本支持降序索引,如果order by之后的字段時(shí)降序的,可以考慮直接創(chuàng)建降序索引,也會(huì)提高查詢效率。
4、Update、Delete的where條件列
對(duì)數(shù)據(jù)按照某個(gè)條件進(jìn)行查詢后再進(jìn)行Update或Delete的操作,如果對(duì)Where字段創(chuàng)建了索引,就能答復(fù)提升效率。原因是因?yàn)樾枰雀鶕?jù)Where條件列檢索出來這條記錄,然后再對(duì)他進(jìn)行更新或刪除。如果進(jìn)行更新的時(shí)候,更新的字段是非索引字段,提升效率會(huì)更明顯,這是因?yàn)橘M(fèi)索引字段更新不需要對(duì)所以進(jìn)行維護(hù)。
比如對(duì)student_info表中的name字段為sdfasdfas123123的數(shù)據(jù)修改student_id為110119,在沒有對(duì)name字段建立索引的情況下,執(zhí)行情況如下:
update student_info set student_id = 110119 where name = 'sdfasdfas123123';#花費(fèi)549ms
添加索引后,執(zhí)行情況如下:
alter table student_info add index idx_name(name); update student_info set student_id = 110119 where name = 'sdfasdfas123123';#花費(fèi)2ms
5、Distinct字段需要?jiǎng)?chuàng)建索引
有時(shí)候需要對(duì)某個(gè)字段進(jìn)行去重,使用Distinct,那么對(duì)這個(gè)創(chuàng)建索引也會(huì)提升查詢效率。
比如查詢課程表中不同student_id都有哪些,如果沒有為student_id創(chuàng)建索引,執(zhí)行情況如下:
select distinct(student_id) from student_id;#花費(fèi)2ms
創(chuàng)建索引后,執(zhí)行情況如下:
alter table student_info add index idx_sid(student_id); select distinct(student_id) from student_id;#花費(fèi)0.1ms
6、多表Join連接操作時(shí),創(chuàng)建索引注意事項(xiàng)
首先,連接表的數(shù)據(jù)量盡量不超過3張,因?yàn)槊吭黾右粡埍砭拖喈?dāng)于增加了一次嵌套的循環(huán),數(shù)量級(jí)增長(zhǎng)非??欤瑖?yán)重影響查詢效率。其次,對(duì)Where條件創(chuàng)建索引,因?yàn)閃here才是對(duì)數(shù)據(jù)條件的過濾,如果再數(shù)據(jù)量非常大的情況下,沒有Where條件過濾時(shí)非常可怕的,最后,對(duì)于連接的字段創(chuàng)建索引,并且改字段再多張表中類型必須一致。
比如,只對(duì)student_id創(chuàng)建索引,查詢結(jié)果如下:
select course_id, name, student_info.student_id,course_name from student_info join course on student_info.course_id = course.course_id where name = 'aAAaAA'; #花費(fèi)176ms
給name字段創(chuàng)建索引后,查詢結(jié)果如下:
alter table student_info add index idx_name(name); select course_id, name, student_info.student_id,course_name from student_info join course on student_info.course_id = course.course_id where name = 'aAAaAA'; #花費(fèi)2ms
7、使用列的類型小的創(chuàng)建索引
這里所說的類型小值意思是該類型表示的數(shù)據(jù)范圍的大小。比如在定義表結(jié)構(gòu)的時(shí)候要顯示的指定列的類型,以整數(shù)類型為例,有TINYINT、MEDIUMINT、INT、BIGINT等,他們占用的存儲(chǔ)空間依次遞增,能表示的數(shù)據(jù)范圍也是一次遞增。如果相對(duì)某個(gè)整數(shù)列建立索引的話,在表示的整數(shù)范圍允許的情況下,盡量讓索引列使用較小的類型,例如能使用INT不要使用BIGINT,能使用MEDIUMINT不使用INT,原因如下:
- 數(shù)據(jù)類型越小,在查詢時(shí)進(jìn)行的比較操作越快
- 數(shù)據(jù)類型越小,索引占用的空間就越少,在一個(gè)數(shù)據(jù)頁內(nèi)就可以存下更多的記錄,從而減少磁盤I/O帶來的性能損耗,也就意味著可以存儲(chǔ)更多的數(shù)據(jù)在數(shù)據(jù)頁中,提高讀寫效率。
上述對(duì)于主鍵來說很合適,因?yàn)樵诰鄞厮饕屑却鎯?chǔ)了數(shù)據(jù),也存儲(chǔ)了索引,可以很好的減少磁盤I/O;而對(duì)于二級(jí)索引來說,還需要一次回表操作才能查到完整的數(shù)據(jù),也就能加了一次磁盤I/O。
8、使用字符串前綴創(chuàng)建索引
根據(jù)Alibaba開發(fā)手冊(cè),在字符串上建立索引時(shí),必須指定索引長(zhǎng)度,沒有必要對(duì)全字段建立索引。
比如有一張商品表,表中的商品描述字段較長(zhǎng),在描述字段上建立前綴索引如下:
create table product(id int, desc varchar(120) not null); alter table product add index(desc(12));
區(qū)分度的計(jì)算可以使用count(distinct left(列名, 索引長(zhǎng)度))/count(*)來確定。
9、區(qū)分度高的列適合作為索引
列的基數(shù)值得時(shí)某一列中不重復(fù)數(shù)據(jù)的個(gè)數(shù),比如說某個(gè)列包含值2,5,3,6,2,7,2,雖然有7條記錄,但該列的基數(shù)卻是5,也就是說,在記錄行數(shù)一定的情況下,列的基數(shù)越大,該列中的值就越分散;列的基數(shù)越小,該列中的值就越集中。這里列的基數(shù)指標(biāo)非常重要,直接影響是否能有效利用索引。最好為列的基數(shù)大的列建立索引,為基數(shù)太小的列建立索引效果反而不好。
可以使用公式select count(distinct col)/count(*) from table
來計(jì)算區(qū)分度,越接近1區(qū)分度越好。
10、使用最頻繁的列放到聯(lián)合索引的左側(cè)
這條就是通常說的最左前綴匹配原則。 通俗來講就是將Where條件后經(jīng)常使用的條件字段放在索引的最左邊,將使用頻率相對(duì)低的放到右邊。
11、在多個(gè)字段都要?jiǎng)?chuàng)建索引的情況下,聯(lián)合索引由于單值索引
二、不適合創(chuàng)建索引
1、在where中使用不到的字段不要設(shè)置索引
通常索引的建立是有代價(jià)的,如果建立索引的字段沒有出現(xiàn)在where條件(包括group by、order by)中,建議一開始就不要?jiǎng)?chuàng)建索引或?qū)⑺饕齽h除,因?yàn)樗饕拇嬖谝矔?huì)占用空間。
2、數(shù)據(jù)量小的表最好不要使用索引
3、有大量重復(fù)數(shù)據(jù)的列上不要建立索引
在條件表達(dá)式中經(jīng)常用到的不同值較多的列上建立索引,但字段中如果有大量重復(fù)數(shù)據(jù),也不用創(chuàng)建索引。比如學(xué)生表中的性別字段,只有男和女兩種值,因此無需建立索引。如果建立索引,不但不會(huì)提高查詢效率,反而會(huì)嚴(yán)重降低數(shù)據(jù)更新速度。
4、避免對(duì)經(jīng)常更新的表創(chuàng)建過多的索引
- 頻繁更新的字段不一定要?jiǎng)?chuàng)建索引,因?yàn)楦聰?shù)據(jù)的時(shí)候,索引也要跟著更新,如果索引太多,更新的時(shí)候會(huì)造成服務(wù)器壓力,從而影響效率。
- 避免對(duì)經(jīng)常更新的表創(chuàng)建過多的索引,并且索引中的列盡可能少。此時(shí)雖然提高了查詢速度,同時(shí)也會(huì)降低更新表的速度。
5、不建議用無序的值作為索引
例如身份證、UUID(在索引比較時(shí)需要轉(zhuǎn)為ASCII,并且插入時(shí)可能造成頁分裂)、MD5、HASH、無序長(zhǎng)字符串等。
6、刪除不在使用或很少使用的索引
表中的數(shù)據(jù)被大量更新或者數(shù)據(jù)的使用方式被改變后,原有的一些索引可能不會(huì)被使用到。DBA應(yīng)定期找出這些索引并將之刪除,從而較少無用索引對(duì)更新操作的影響。
7、不要定義冗余或重復(fù)的索引
例如身份證、UUID(在索引比較時(shí)需要轉(zhuǎn)為ASCII,并且插入時(shí)可能造成頁分裂)、MD5、HASH、無序長(zhǎng)字符串等。
8、刪除不在使用或很少使用的索引
表中的數(shù)據(jù)被大量更新或者數(shù)據(jù)的使用方式被改變后,原有的一些索引可能不會(huì)被使用到。DBA應(yīng)定期找出這些索引并將之刪除,從而較少無用索引對(duì)更新操作的影響。
9、不要定義冗余或重復(fù)的索引
總結(jié)
到此這篇關(guān)于MySQL索引創(chuàng)建原則的文章就介紹到這了,更多相關(guān)MySQL索引創(chuàng)建原則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MySQL創(chuàng)建索引/判斷索引是否生效的問題
- Mysql創(chuàng)建json字段索引的兩種方式
- mysql創(chuàng)建索引的3種方法實(shí)例
- mysql error 1071: 創(chuàng)建唯一索引時(shí)字段長(zhǎng)度限制的問題
- MySQL創(chuàng)建唯一索引時(shí)報(bào)錯(cuò)Duplicate?entry?*?for?key問題
- MySQL為JSON字段創(chuàng)建索引方式(Multi-Valued?Indexes?多值索引)
- MySql索引和索引創(chuàng)建策略
- MySQL創(chuàng)建高性能索引的全步驟
- MySQL不適合創(chuàng)建索引的11種情況示例分析
相關(guān)文章
詳解數(shù)據(jù)庫多表連接查詢的實(shí)現(xiàn)方法
這篇文章主要介紹了詳解數(shù)據(jù)庫多表連接查詢的實(shí)現(xiàn)方法的相關(guān)資料,希望通過本文大家能夠掌握數(shù)據(jù)庫多表查詢的方法,需要的朋友可以參考下2017-09-09AlmaLinux 9 安裝 MySQL 8.0.32的詳細(xì)過程
這篇文章主要介紹了AlmaLinux 9 安裝 MySQL 8.0.32的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04mysql如何通過當(dāng)前排序字段獲取相鄰數(shù)據(jù)項(xiàng)
這篇文章主要介紹了mysql如何通過當(dāng)前排序字段獲取相鄰數(shù)據(jù)項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05詳細(xì)聊一聊mysql的樹形結(jié)構(gòu)存儲(chǔ)以及查詢
由于mysql是關(guān)系型數(shù)據(jù)庫,因此對(duì)于類似組織架構(gòu),子任務(wù)等相關(guān)的樹形結(jié)構(gòu)的處理不是很友好,下面這篇文章主要給大家介紹了關(guān)于mysql樹形結(jié)構(gòu)存儲(chǔ)以及查詢的相關(guān)資料,需要的朋友可以參考下2022-04-04關(guān)于MySQL中“Insert into select“ 的死鎖情況分析
這篇文章主要介紹了關(guān)于MySQL中“Insert into select“ 的死鎖情況分析,死鎖是指兩個(gè)或者多個(gè)事務(wù)在同一資源上的相互占用,并請(qǐng)求鎖定對(duì)方占用的資源,從而導(dǎo)致惡性循環(huán)的現(xiàn)象,需要的朋友可以參考下2023-05-05