數據庫的索引可以加快查詢速度,原因是索引使用特定的數據結構(B-Tree)對特定的列額外組織存放,加快存儲引擎(索引是存儲引擎實現)查找記錄的速度。
索引優化是數據庫優化的最重要手段。
如果查詢語句使用索引(通常是where條件匹配索引)就會利用樹的結構加快查找,索引會按值查找到要查找的行在表中位置,不需回表查詢數據的就是聚簇索引(索引和數據存放在一起)。通常是需要回表再查數據,需要消耗額外的磁盤IO。所以有些時候(如按順序讀取數據)全表掃描會比使用索引快的原因就在於此。
查詢條件只有一個字段時,在該字段建立索引即可,可優化的地方是對於text blob字段使用前綴索引。
當查詢條件有多個字段時,單列索引和多列索引有很大的區別。如果使用多列索引,where條件中字段的順序非常重要,需要滿足最左前綴列。最左前綴:查詢條件中的所有字段需要從左邊起按順序出現在多列索引中,查詢條件的字段數要小於等於多列索引的字段數,中間字段不能存在范圍查詢的字段(<,like等),這樣的sql可以使用該多列索引。
MySQL多列索引適合的場景
1.全字段匹配
2.匹配部分最左前綴
3.匹配第一列
4.匹配第一列范圍查詢(可用用like a%,但不能使用like %b)
5.精確匹配某一列和和范圍匹配另外一列
order by操作中出現的字段同樣適用於按值查找的規則,where+order by中出現的字段需可以建立滿足如上五種規則多列索引。
使用多列所需需要按照最左索引列查找;不能跳過中間列;如果某一列是范圍查詢,那么其右邊所有列無法使用索引。
IN什么情況下是范圍查詢,什么情況下是多個等值查詢?如果有order by排序時,多個等於條件查詢就是范圍查詢,沒有order by排序就沒有限制。
例如,建立多列索引(name, age, id),
只能使用索引的前兩列。in是范圍查詢
... where name='nginx.cn' and age in(15,16,17) order by id
可以使用整個索引,in是按值查詢
... where name='nginx.cn' and age in(15,16,17) and id ='3'
通過實例理解單列索引、多列索引以及最左前綴原則
實例:現在我們想查出滿足以下條件的用戶id:
mysql>SELECT `uid` FROM people WHERE lname`='Liu' AND `fname`='Zhiqun' AND `age`=26
因為我們不想掃描整表,故考慮用索引。
單列索引:
ALTER TABLE people ADD INDEX lname (lname);
將lname列建索引,這樣就把范圍限制在lname='Liu'的結果集1上,之后掃描結果集1,產生滿足fname='Zhiqun'的結果集2,再掃描結果集2,找到 age=26的結果集3,即最終結果。
由 於建立了lname列的索引,與執行表的完全掃描相比,效率提高了很多,但我們要求掃描的記錄數量仍舊遠遠超過了實際所需 要的。雖然我們可以刪除lname列上的索引,再創建fname或者age 列的索引,但是,不論在哪個列上創建索引搜索效率仍舊相似。
2.多列索引:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
為了提高搜索效率,我們需要考慮運用多列索引,由於索引文件以B-Tree格式保存,所以我們不用掃描任何記錄,即可得到最終結果。
注:在mysql中執行查詢時,只能使用一個索引,如果我們在lname,fname,age上分別建索引,執行查詢時,只能使用一個索引,mysql會選擇一個最嚴格(獲得結果集記錄數最少)的索引。
3.最左前綴:顧名思義,就是最左優先,上例中我們創建了lname_fname_age多列索引,相當於創建了(lname)單列索引,(lname,fname)組合索引以及(lname,fname,age)組合索引。
注:在創建多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。