sql索引的建立与使用_sqlserver创建索引语句(廖雪峰的官方网站)
之前在網(wǎng)上看到過很多關(guān)于mysql聯(lián)合索引最左前綴匹配的文章,自以為就了解了其原理,發(fā)現(xiàn)遺漏了些東西,這里自己整理一下這方面的內(nèi)容。
1 前言
SQL索引有兩種,聚集索引和非聚集索引
聚集索引存儲(chǔ)記錄是物理上連續(xù)存在,而非聚集索引是邏輯上的連續(xù),物理存儲(chǔ)并不連續(xù)
字典的拼音查詢法就是聚集索引,字典的部首查詢就是一個(gè)非聚集索引.
聚集索引和非聚集索引的根本區(qū)別是表記錄的排列順序和與索引的排列順序是否一致
聚集索引一個(gè)表只能有一個(gè),而非聚集索引一個(gè)表可以存在多個(gè)。
2 建立索引的原則:
1) 定義主鍵的數(shù)據(jù)列一定要建立索引。
2) 定義有外鍵的數(shù)據(jù)列一定要建立索引。
3) 對(duì)于經(jīng)常查詢的數(shù)據(jù)列最好建立索引。
4) 對(duì)于需要在指定范圍內(nèi)的快速或頻繁查詢的數(shù)據(jù)列;
5) 經(jīng)常用在WHERE子句中的數(shù)據(jù)列。
6) 經(jīng)常出現(xiàn)在關(guān)鍵字order by、group by、distinct后面的字段,建立索引。
如果建立的是復(fù)合索引,索引的字段順序要和這些關(guān)鍵字后面的字段順序一致,否則索引不會(huì)被使用。
7) 對(duì)于那些查詢中很少涉及的列,重復(fù)值比較多的列不要建立索引。
8) 對(duì)于定義為text、image和bit的數(shù)據(jù)類型的列不要建立索引。
9) 對(duì)于經(jīng)常存取的列避免建立索引
10) 限制表上的索引數(shù)目。對(duì)一個(gè)存在大量更新操作的表,所建索引的數(shù)目一般不要超過3個(gè),最多不要超過5個(gè)。
索引雖說提高了訪問速度,但太多索引會(huì)影響數(shù)據(jù)的更新操作。
11) 對(duì)復(fù)合索引,按照字段在查詢條件中出現(xiàn)的頻度建立索引。在復(fù)合索引中,記錄首先按照第一個(gè)字段排序。
對(duì)于在第一個(gè)字段上取值相同的記錄,系統(tǒng)再按照第二個(gè)字段的取值排序,以此類推。
因此只有復(fù)合索引的第一個(gè)字段出現(xiàn)在查詢條件中,該索引才可能被使用,因此將應(yīng)用頻度高的字段,放置在復(fù)合索引的前面,會(huì)使系統(tǒng)最大可能地使用此索引,發(fā)揮索引的作用。
2.1另外原則
1.最左前綴匹配原則
非常重要的原則,mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c >3 and d = 4. 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。
2.=和in可以亂序
比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優(yōu)化器會(huì)幫你優(yōu)化成索引可以識(shí)別的形式
3.盡量選擇區(qū)分度高的列作為索引
區(qū)分度的公式是count(distinct col)/count(*),表示字段不重復(fù)的比例,比例越大我們掃描的記錄數(shù)越少,唯一鍵的區(qū)分度是1,而一些狀態(tài)、性別字段可能在大數(shù)據(jù)面前區(qū)分度就是0,那可能有人會(huì)問,這個(gè)比例有什么經(jīng)驗(yàn)值嗎?使用場(chǎng)景不同,這個(gè)值也很難確定,一般需要join的字段我們都要求是0.1以上,即平均1條掃描10條記錄
4.索引列不能參與計(jì)算
保持列“干凈”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡(jiǎn)單,b+樹中存的都是數(shù)據(jù)表中的字段值,但進(jìn)行檢索時(shí),需要把所有元素都應(yīng)用函數(shù)才能比較,顯然成本太大。所以語句應(yīng)該寫成create_time = unix_timestamp(’2014-05-29’);
5.盡量的擴(kuò)展索引,不要新建索引。
比如表中已經(jīng)有a的索引,現(xiàn)在要加(a,b)的索引,那么只需要修改原來的索引即可
6.選擇唯一性索引
唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄。例如,學(xué)生表中學(xué)號(hào)是具有唯一性的字段。為該字段建立唯一性索引可以很快的確定某個(gè)學(xué)生的信息。如果使用姓名的話,可能存在同名現(xiàn)象,從而降低查詢速度。
7.為經(jīng)常需要排序、分組和聯(lián)合操作的字段建立索引
經(jīng)常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作會(huì)浪費(fèi)很多時(shí)間。如果為其建立索引,可以有效地避免排序操作。
8.為常作為查詢條件的字段建立索引
如果某個(gè)字段經(jīng)常用來做查詢條件,那么該字段的查詢速度會(huì)影響整個(gè)表的查詢速度。因此,為這樣的字段建立索引,可以提高整個(gè)表的查詢速度。
9.限制索引的數(shù)目
索引的數(shù)目不是越多越好。每個(gè)索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大。修改表時(shí),對(duì)索引的重構(gòu)和更新很麻煩。越多的索引,會(huì)使更新表變得很浪費(fèi)時(shí)間。
10.盡量使用數(shù)據(jù)量少的索引
如果索引的值很長(zhǎng),那么查詢的速度會(huì)受到影響。例如,對(duì)一個(gè)CHAR(100)類型的字段進(jìn)行全文檢索需要的時(shí)間肯定要比對(duì)CHAR(10)類型的字段需要的時(shí)間要多。
11.盡量使用前綴來索引
如果索引字段的值很長(zhǎng),最好使用值的前綴來索引。例如,TEXT和BLOG類型的字段,進(jìn)行全文檢索會(huì)很浪費(fèi)時(shí)間。如果只檢索字段的前面的若干個(gè)字符,這樣可以提高檢索速度。
12.刪除不再使用或者很少使用的索引
表中的數(shù)據(jù)被大量更新,或者數(shù)據(jù)的使用方式被改變后,原有的一些索引可能不再需要。數(shù)據(jù)庫(kù)管理員應(yīng)當(dāng)定期找出這些索引,將它們刪除,從而減少索引對(duì)更新操作的影響。
2.2 最左前綴匹配原則
在mysql建立聯(lián)合索引時(shí)會(huì)遵循最左前綴匹配的原則,即最左優(yōu)先,在檢索數(shù)據(jù)時(shí)從聯(lián)合索引的最左邊開始匹配,示例:
對(duì)列col1、列col2和列col3建一個(gè)聯(lián)合索引
KEY test_col1_col2_col3 on test(col1,col2,col3);
聯(lián)合索引 test_col1_col2_col3 實(shí)際建立了(col1)、(col1,col2)、(col,col2,col3)三個(gè)索引。
SELECT*FROMtestWHEREcol1=“1”ANDclo2=“2”ANDclo4=“4”
上面這個(gè)查詢語句執(zhí)行時(shí)會(huì)依照最左前綴匹配原則,檢索時(shí)會(huì)使用索引(col1,col2)進(jìn)行數(shù)據(jù)匹配。
注意
索引的字段可以是任意順序的,如:
SELECT * FROM test WHERE col1=“1” AND clo2=“2”
SELECT * FROM test WHERE col2=“2” AND clo1=“1”
這兩個(gè)查詢語句都會(huì)用到索引(col1,col2),mysql創(chuàng)建聯(lián)合索引的規(guī)則是首先會(huì)對(duì)聯(lián)合合索引的最左邊的,也就是第一個(gè)字段col1的數(shù)據(jù)進(jìn)行排序,在第一個(gè)字段的排序基礎(chǔ)上,然后再對(duì)后面第二個(gè)字段col2進(jìn)行排序。其實(shí)就相當(dāng)于實(shí)現(xiàn)了類似 order by col1 col2這樣一種排序規(guī)則。
有人會(huì)疑惑第二個(gè)查詢語句不符合最左前綴匹配:首先可以肯定是兩個(gè)查詢語句都包含索引(col1,col2)中的col1、col2兩個(gè)字段,只是順序不一樣,查詢條件一樣,最后所查詢的結(jié)果肯定是一樣的。既然結(jié)果是一樣的,到底以何種順序的查詢方式最好呢?此時(shí)我們可以借助mysql查詢優(yōu)化器explain,explain會(huì)糾正sql語句該以什么樣的順序執(zhí)行效率最高,最后才生成真正的執(zhí)行計(jì)劃。
2.3 為什么要使用聯(lián)合索引
- 減少開銷。建一個(gè)聯(lián)合索引(col1,col2,col3),實(shí)際相當(dāng)于建了(col1),(col1,col2),(col1,col2,col3)三個(gè)索引。每多一個(gè)索引,都會(huì)增加寫操作的開銷和磁盤空間的開銷。對(duì)于大量數(shù)據(jù)的表,使用聯(lián)合索引會(huì)大大的減少開銷!
- 覆蓋索引。對(duì)聯(lián)合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通過遍歷索引取得數(shù)據(jù),而無需回表,這減少了很多的隨機(jī)io操作。減少io操作,特別的隨機(jī)io其實(shí)是dba主要的優(yōu)化策略。所以,在真正的實(shí)際應(yīng)用中,覆蓋索引是主要的提升性能的優(yōu)化手段之一。
- 效率高。索引列越多,通過索引篩選出的數(shù)據(jù)越少。有1000W條數(shù)據(jù)的表,有如下sql:selectfrom table where col1=1 and col2=2 and col3=3,假設(shè)假設(shè)每個(gè)條件可以篩選出10%的數(shù)據(jù),如果只有單值索引,那么通過該索引能篩選出1000W10%=100w條數(shù)據(jù),然后再回表從100w條數(shù)據(jù)中找到符合col2=2 and col3= 3的數(shù)據(jù),然后再排序,再分頁;如果是聯(lián)合索引,通過索引篩選出1000w10%10% *10%=1w,效率提升可想而知!
引申
對(duì)于聯(lián)合索引(col1,col2,col3),查詢語句SELECT * FROM test WHERE col2=2;是否能夠觸發(fā)索引?
大多數(shù)人都會(huì)說NO,實(shí)際上卻是YES。
原因:
EXPLAIN SELECT * FROM test WHERE col2=2;
EXPLAIN SELECT * FROM test WHERE col1=1;
觀察上述兩個(gè)explain結(jié)果中的type字段。查詢中分別是:
- type: index
- type: ref
index:這種類型表示mysql會(huì)對(duì)整個(gè)該索引進(jìn)行掃描。要想用到這種類型的索引,對(duì)這個(gè)索引并無特別要求,只要是索引,或者某個(gè)聯(lián)合索引的一部分,mysql都可能會(huì)采用index類型的方式掃描。但是呢,缺點(diǎn)是效率不高,mysql會(huì)從索引中的第一個(gè)數(shù)據(jù)一個(gè)個(gè)的查找到最后一個(gè)數(shù)據(jù),直到找到符合判斷條件的某個(gè)索引。所以,上述語句會(huì)觸發(fā)索引。
ref:這種類型表示mysql會(huì)根據(jù)特定的算法快速查找到某個(gè)符合條件的索引,而不是會(huì)對(duì)索引中每一個(gè)數(shù)據(jù)都進(jìn)行一一的掃描判 斷,也就是所謂你平常理解的使用索引查詢會(huì)更快的取出數(shù)據(jù)。而要想實(shí)現(xiàn)這種查找,索引卻是有要求的,要實(shí)現(xiàn)這種能快速查找的算法,索引就要滿足特定的數(shù)據(jù)結(jié)構(gòu)。簡(jiǎn)單說,也就是索引字段的數(shù)據(jù)必須是有序的,才能實(shí)現(xiàn)這種類型的查找,才能利用到索引。
3 聚集索引和非聚集索引
聚集索引和非聚集索引的根本區(qū)別是數(shù)據(jù)記錄的排列順序和索引的排列順序是否一致,聚集索引表記錄的排列順序與索引的排列順序一致,優(yōu)點(diǎn)是查詢速度快,因?yàn)橐坏┚哂械谝粋€(gè)索引值的紀(jì)錄被找到,具有連續(xù)索引值的記錄也一定物理的緊跟其后,從而縮小了搜索范圍,對(duì)于返回某一范圍的數(shù)據(jù)效果最好。
聚集索引的缺點(diǎn)是對(duì)表進(jìn)行修改速度較慢,這是為了保持表中的記錄的物理順序與索引的順序一致,而把記錄插入到數(shù)據(jù)頁的相應(yīng)位置,必須在數(shù)據(jù)頁中進(jìn)行數(shù)據(jù)重排,降低了執(zhí)行速度。
非聚集索引指定了表中記錄的邏輯順序,數(shù)據(jù)記錄的物理順序和索引的順序不一致,聚集索引和非聚集索引都采用了B樹的結(jié)構(gòu),但非聚集索引的葉子層順序并不與實(shí)際的數(shù)據(jù)頁相同,而采用指向表中的記錄在數(shù)據(jù)頁中位置的方式。非聚集索引比聚集索引層次多,添加記錄不會(huì)引起數(shù)據(jù)順序的重組。在有大量不同數(shù)據(jù)的列上建立非聚集索引,可以提高數(shù)據(jù)的查詢和修改速度。
在對(duì)聚集索引列查詢時(shí),聚集索引的速度要比非聚集索引速度快。
在對(duì)聚集索引列排序時(shí),聚集索引的速度要比非聚集索引速度快。但是如果數(shù)據(jù)量比較大時(shí),如10萬以上,則二者的速度差別不明顯。
3.1 聚集索引和非聚集的建立原則
在創(chuàng)建索引時(shí)要做到三個(gè)適當(dāng),即在適當(dāng)?shù)谋砩稀⑦m當(dāng)?shù)牧猩蟿?chuàng)建適當(dāng)數(shù)量的索引。雖然這可以通過一句話來概括優(yōu)化的索引的 基本準(zhǔn)則,但是要做到這一點(diǎn)的話,需要做出很大的努力。具體的來說,要做到這個(gè)三個(gè)適當(dāng)有如下幾個(gè)要求。
3.1.1根據(jù)表的大小來創(chuàng)建索引。
雖然給表創(chuàng)建索引,可以提高查詢的效率。但是需要注意的是,索引也需要一定的開銷的。為此并不是說給所有的表都創(chuàng)建索引,那么就可以提高數(shù)據(jù)庫(kù)的性能。這個(gè)認(rèn)識(shí)是錯(cuò)誤的。給所有的表都創(chuàng)建了索引,那么其反而會(huì)給數(shù)據(jù)庫(kù)的性能造成負(fù)面的影響。因?yàn)榇藭r(shí)濫用索引的開銷可能已經(jīng)遠(yuǎn)遠(yuǎn)大于由此帶來的性能方面的收益。所以,數(shù)據(jù)庫(kù)管理員首先需要做到,為合適的表來建立索引,而不是為所有的表建立索引。
一般來說,不需要為比較小的表創(chuàng)建索引。因?yàn)榧词菇⒘怂饕湫阅芤膊粫?huì)得到很大的改善。相反索引建立的開銷,如維護(hù)成本等等,要比這個(gè)要大。也就是說,付出的要比得到的多,顯然違反常理。
另外,就是對(duì)于超大的表,也不一定要建立索引。有些表雖然比較大,記錄數(shù)量非常的多。但是此時(shí)為這個(gè)表建立索引并一定的合適。對(duì)于一些超大的表,建立索引有時(shí)候往往不能夠達(dá)到預(yù)計(jì)的效果。而且在大表上建立索引,其索引的開銷要比普通的表大的多。那么到底是否給大表建立索引呢?主要是看兩個(gè)方面的內(nèi)容。首先是需要關(guān)注一下,在這張大表中經(jīng)常需要查詢的記錄數(shù)量。一般來說,如果經(jīng)常需要查詢的數(shù)據(jù)不超過10%到15%的話,那就沒有必要為其建立索引的必要。因?yàn)榇藭r(shí)建立索引的開銷可能要比性能的改善大的多。如果數(shù)據(jù)庫(kù)管理員需要得出一個(gè)比較精確的結(jié)論,那么就需要進(jìn)行測(cè)試分析。
3.1.2根據(jù)列的特征來創(chuàng)建索引
列的特點(diǎn)不同,索引創(chuàng)建的效果也不同。需要了解為哪些列創(chuàng)建索引可以起到事半功倍的效果。同時(shí)也需要了解為哪些列創(chuàng)建索引反而起到的是事倍功半的效果。
索引設(shè)置的是否恰當(dāng),不僅跟數(shù)據(jù)庫(kù)設(shè)計(jì)架構(gòu)有關(guān),而且還跟企業(yè)的經(jīng)濟(jì)業(yè)務(wù)相關(guān)。雖然一開始已經(jīng)做了索引的優(yōu)化工作。但是隨著后來經(jīng)濟(jì)數(shù)據(jù)的增加,這個(gè)索引的效果會(huì)越來越打折扣。所以需要隔一段時(shí)間,對(duì)數(shù)據(jù)庫(kù)的索引進(jìn)行優(yōu)化。該去掉的去掉,該調(diào)整的調(diào)整,以提高數(shù)據(jù)庫(kù)的性能。
3.1.3在一個(gè)表上創(chuàng)建多少索引合適
通常來說,表的索引越多,其查詢的速度也就越快。但是,表的更新速度則會(huì)降低。這主要是因?yàn)楸淼母峦瑫r(shí)也是索引的更新。到底在表中創(chuàng)建多少索引合適,就需要在這個(gè)更新速度與查詢速度之間取得一個(gè)均衡點(diǎn)。如對(duì)于一些數(shù)據(jù)倉(cāng)庫(kù)或者決策型數(shù)據(jù)庫(kù)系統(tǒng),其主要用來進(jìn)行查詢。相關(guān)的記錄往往是在數(shù)據(jù)庫(kù)初始化的時(shí)候?qū)搿4藭r(shí),設(shè)置的索引多一點(diǎn),可以提高數(shù)據(jù)庫(kù)的查詢性能。同時(shí)因?yàn)橛涗洸辉趺锤拢运饕容^多的情況下,也不會(huì)影響到更新的速度。相反,如果那些表中經(jīng)常需要更新記錄,如一些事務(wù)型的應(yīng)用系統(tǒng),數(shù)據(jù)更新操作是家常便飯的事情。此時(shí)如果在一張表中建立過多的索引,則會(huì)影響到更新的速度。由于更新操作比較頻繁,所以對(duì)其的負(fù)面影響,要比查詢效率提升要大的多。此時(shí)就需要限制索引的數(shù)量,只在一些必要的字段上建立索引。
4 索引的不足之處
雖然索引大大提高了查詢速度,同時(shí)卻會(huì)降低更新表的速度,如對(duì)表進(jìn)行INSERT、UPDATE和DELETE。因?yàn)楦卤頃r(shí),MySQL不僅要保存數(shù)據(jù),還要保存一下索引文件。
建立索引會(huì)占用磁盤空間的索引文件。一般情況這個(gè)問題不太嚴(yán)重,但如果你在一個(gè)大表上創(chuàng)建了多種組合索引,索引文件的會(huì)膨脹很快。
索引只是提高效率的一個(gè)因素,如果你的MySQL有大數(shù)據(jù)量的表,就需要花時(shí)間研究建立最優(yōu)秀的索引,或優(yōu)化查詢語句。
5 使用索引時(shí),有以下一些技巧和注意事項(xiàng):
5.1 索引不會(huì)包含有NULL值的列
只要列中包含有NULL值都將不會(huì)被包含在索引中,復(fù)合索引中只要有一列含有NULL值,那么這一列對(duì)于此復(fù)合索引就是無效的。
所以我們?cè)跀?shù)據(jù)庫(kù)設(shè)計(jì)時(shí)不要讓字段的默認(rèn)值為NULL。
5.2 使用短索引
對(duì)列進(jìn)行索引,如果可能應(yīng)該指定一個(gè)前綴長(zhǎng)度。
例如,如果有一個(gè)CHAR(255)的列,如果在前10個(gè)或20個(gè)字符內(nèi),多數(shù)值是惟一的,那么就不要對(duì)整個(gè)列進(jìn)行索引。
短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。
5.3 索引列排序
MySQL查詢只使用一個(gè)索引,因此如果where子句中已經(jīng)使用了索引的話,那么order by中的列是不會(huì)使用索引的。
因此數(shù)據(jù)庫(kù)默認(rèn)排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個(gè)列的排序,如果需要最好給這些列創(chuàng)建復(fù)合索引。
5.4 like語句操作
一般情況下不鼓勵(lì)使用like操作,如果非使用不可,如何使用也是一個(gè)問題。
like “%aaa%” 不會(huì)使用索引,而like “aaa%”可以使用索引。
5.5 不要在列上進(jìn)行運(yùn)算
select * from users where YEAR(adddate)<2007;
將在每個(gè)行上進(jìn)行運(yùn)算,這將導(dǎo)致索引失效而進(jìn)行全表掃描,因此我們可以改成
select * from users where adddate<‘2007-01-01’;
5.6 不使用NOT IN和<>操作
7 索引的建立時(shí)機(jī)
一般來說,在WHERE和JOIN中出現(xiàn)的列需要建立索引,但也不完全如此,
因?yàn)镸ySQL只對(duì)<,<=,=,>,>=,BETWEEN,IN,以及某些時(shí)候的LIKE才會(huì)使用索引。
因?yàn)樵谝酝ㄅ浞?和_開頭作查詢時(shí),MySQL不會(huì)使用索引。
8 索引的使用
8.1 建立索引
create [UNIQUE|FULLTEXT] index index_name on tbl_name (col_name [(length)] [ASC | DESC] , …..);
示例:
alter table table_name ADD INDEX [index_name] (index_col_name,…)
CREATE INDEX paywayid_index ON pay_order_trade (paywayid)
8.2 組合索引
CREATE INDEX idx_example ON table1 (col1 ASC, col2 DESC, col3 ASC)
示例:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
最左前綴:顧名思義,就是最左優(yōu)先,
上例中我們創(chuàng)建了lname_fname_age多列索引,相當(dāng)于創(chuàng)建了(lname)單列索引,(lname,fname)組合索引以及(lname,fname,age)組合索引。
8.3 刪除索引
DROP INDEX index_name ON tbl_name;
alter table table_name drop index index_name;
8.4 刪除主鍵(索引)比較特別:
alter table t_b drop primary key;
8.5 查詢索引(均可)
show index from table_name;
show keys from table_name;
desc table_Name;
9查詢慢分析
9.1 回到開始的慢查詢
根據(jù)最左匹配原則,最開始的sql語句的索引應(yīng)該是status、operator_id、type、operate_time的聯(lián)合索引;其中status、operator_id、type的順序可以顛倒,所以我才會(huì)說,把這個(gè)表的所有相關(guān)查詢都找到,會(huì)綜合分析;比如還有如下查詢:
select * from task where status = 0 and type = 12 limit 10;
select count(*) from task where status = 0 ;
那么索引建立成(status,type,operator_id,operate_time)就是非常正確的,因?yàn)榭梢愿采w到所有情況。這個(gè)就是利用了索引的最左匹配的原則
9.2 查詢優(yōu)化神器 – explain命令
關(guān)于explain命令相信大家并不陌生,具體用法和字段含義可以參考官網(wǎng)explain-output,這里需要強(qiáng)調(diào)rows是核心指標(biāo),絕大部分rows小的語句執(zhí)行一定很快(有例外,下面會(huì)講到)。所以優(yōu)化語句基本上都是在優(yōu)化rows。
9.3 慢查詢優(yōu)化基本步驟
- 先運(yùn)行看看是否真的很慢,注意設(shè)置SQL_NO_CACHE
- where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應(yīng)用到表中返回的記錄數(shù)最小的表開始查起,單表每個(gè)字段分別查詢,看哪個(gè)字段的區(qū)分度最高
- explain查看執(zhí)行計(jì)劃,是否與1預(yù)期一致(從鎖定記錄較少的表開始查詢)
- order by limit 形式的sql語句讓排序的表優(yōu)先查
- 了解業(yè)務(wù)方使用場(chǎng)景
- 加索引時(shí)參照建索引的幾大原則
- 觀察結(jié)果,不符合預(yù)期繼續(xù)從0分析
索引的優(yōu)化方法
1,何時(shí)使用聚簇索引或非聚簇索引:
|
動(dòng)作描述 |
使用聚集索引 |
使用非聚集索引 |
|
列經(jīng)常被分組排序 |
應(yīng) |
應(yīng) |
|
返回某范圍內(nèi)的數(shù)據(jù) |
應(yīng) |
不應(yīng) |
|
一個(gè)或極少不同值 |
不應(yīng) |
不應(yīng) |
|
小數(shù)目的不同值 |
應(yīng) |
不應(yīng) |
|
大數(shù)目的不同值 |
不應(yīng) |
應(yīng) |
|
頻繁更新的列 |
不應(yīng) |
應(yīng) |
|
外鍵列 |
應(yīng) |
應(yīng) |
|
主鍵列 |
應(yīng) |
應(yīng) |
|
頻繁修改索引列 |
不應(yīng) |
應(yīng) |
2,索引不會(huì)包含有NULL值的列:只要列中包含有NULL值,都將不會(huì)被包含在索引中,組合索引中只要有一列有NULL值,那么這一列對(duì)于此條組合索引就是無效的。所以我們?cè)跀?shù)據(jù)庫(kù)設(shè)計(jì)時(shí),不要讓索引字段的默認(rèn)值為NULL。
3,使用短索引:假設(shè),如果有一個(gè)數(shù)據(jù)類型為CHAR(255)的列,在前10個(gè)或20個(gè)字符內(nèi),絕大部分?jǐn)?shù)據(jù)的值是唯一的,那么就不要對(duì)整個(gè)列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省I/O操作。
4,索引列排序:MySQL查詢只使用一個(gè)索引,因此如果WHERE子句中已經(jīng)使用了索引的話,那么ORDER BY中的列是不會(huì)使用索引的。因此數(shù)據(jù)庫(kù)默認(rèn)排序可以符合要求的情況下,不要使用排序操作;盡量不要包含多個(gè)列的排序,如果需要,最好給這些列也創(chuàng)建組合索引。
5,LIKE語句操作:一般情況下,不建議使用LIKE操作;如果非使用不可,如何使用也是一個(gè)研究的課題。LIKE “%aaaaa%”不會(huì)使用索引,但是LIKE “aaa%”卻可以使用索引。
6,不要在索引列上進(jìn)行運(yùn)算:在建立索引的原則中,提到了索引列不能進(jìn)行運(yùn)算,這里就不再贅述了。
mysql索引失效情況
1、最佳左前綴原則——如果索引了多列,要遵守最左前綴原則。指的是查詢要從索引的最左前列開始并且不跳過索引中的列。
前提條件:表中已添加復(fù)合索引(username,password,age)
分析:該查詢?nèi)鄙賣sername,查詢條件復(fù)合索引最左側(cè)username缺少,違反了最佳左前綴原則,導(dǎo)致索引失效,變?yōu)锳LL,全表掃描
分析:查詢條件缺少username,password,查詢條件復(fù)合索引最左側(cè)username,password缺少,違反了最佳左前綴原則,導(dǎo)致索引失效,變?yōu)锳LL,全表掃描
分析:該查詢只有一個(gè)username條件,根據(jù)最佳左前綴原則索引能夠被使用到,但是是部分使用
2、不在索引列上做任何操作(計(jì)算,函數(shù),(自動(dòng)或者手動(dòng))類型裝換),會(huì)導(dǎo)致索引失效而導(dǎo)致全表掃描
分析:第一個(gè)圖索引列不使用函數(shù),遵循左前綴原則,能夠使用索引。第二張圖索引列上使用了函數(shù),即使遵循左前綴原則,索引還是失效
3、存儲(chǔ)引擎不能使用索引中范圍條件右邊的列,范圍之后索引失效。(< ,> between and)
分析:圖一索引全部使用到。圖二索引使用到username和age,但是username是使用索引檢索,而age著重索引排序,這時(shí)age為范圍查找,password索引將失效
4、mysql使用不等于(!= 或者<>)的時(shí)候,無法使用索引,會(huì)導(dǎo)致索引失效
5、mysql中使用is not null 或者 is null會(huì)導(dǎo)致無法使用索引
分析:對(duì)username列做了普通索引,查詢帶is not null,結(jié)果索引不生效
6、mysql中l(wèi)ike查詢是以%開頭,索引會(huì)失效變成全表掃描,覆蓋索引。
分析:對(duì)username列做了普通索引,以%開頭進(jìn)行查詢,結(jié)果索引失效被覆蓋
7、mysql中,字符串不加單引號(hào)索引會(huì)失效。正確寫法:select * from t_user where username = ‘lujin’;
8、mysql中,如果條件中有or,即使其中有條件帶索引也不會(huì)使用(這也是為什么盡量少用or的原因)。要想使用or,又想讓索引生效,只能將or條件中的每個(gè)列都加上索引
9、如果mysql使用全表掃描要比使用索引快,則不會(huì)使用到索引
參考:
https://blog.csdn.net/fly910905/article/details/78690074
https://tech.meituan.com/2014/06/30/mysql-index.html
https://segmentfault.com/a/1190000015416513
https://www.cnblogs.com/Jessy/p/3543063.html
https://blog.csdn.net/qq_34258346/article/details/80272198
總結(jié)
以上是生活随笔為你收集整理的sql索引的建立与使用_sqlserver创建索引语句(廖雪峰的官方网站)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【图嵌入】DeepWalk原理与代码实战
- 下一篇: 拯救U盘之——轻松修复U盘“无法访问”的