MySQL中 提高性能 的一個最有效的方式是對數據表 設計合理的索引。索引提供了高效訪問數據的方法,并且加快查詢的速度,因此索引對查詢的速度有著至關重要的影響。使用索引可以 快速地定位 表中的某條記錄,從而提高數據庫査詢的速度,提高數據庫的性能。.如果查詢時沒有使用索引,查詢語句就會掃描表中的所有記錄。在數據量大的情況下,這樣查詢的速度會很慢。
大多數情況下都(默認)采用 B+樹 來構建索引。只是空間列類型的索引使用 R-樹 ,并且MEMORY表還支持 hash索引。其實,用不用索引,最終都是優化器說了算。優化器是基于什么的優化器?基于cost開銷(CostBase0ptimizer),它不是基于規則(Rule-Basedoptimizer),也不是基于 語義。怎么樣開銷小就怎么來。另外,SQL語句是否使用索引,跟數據庫版本、數據量、數據選擇度都有關系。
以下是數據庫中索引失效常見的11種情況:
1、全職匹配我最愛:
假如有三個索引:索引1是對字段name添加的索引,索引2是對字段(name,class_id)添加了聯合索引,索引3是對字段(name,class_id,age)添加的聯合索引;
在進行查詢中條件判斷包含字段(name,class_id,age)時,會優先使用索引3,相當于索引1、索引2失效。
2、最佳左前綴法則:
在MySQL建立聯合索引時會遵守最佳左前綴原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。
例如索引(name,class_id,age),只有查詢(name),(name,class_id),(name,class_id,age)會走索引,而(class_id),(class_id,age),(age)都不會走索引。
MySQL可以為多個字段創建索引,一個索引可以包括16個字段。對于多列索引,過濾條件要使用索引必須按照索引建立時的順序,從左到右,依次滿足,一旦跳過某個字段,索引后面的字段都無法被使用。如果查詢條件中沒有使用這些字段中第1個字段時,多列(或聯合)索引不會被使用。
3、主鍵插入順序
對于一個使用 InnoDB 存儲引擎的表來說,在我們沒有顯式的創建索引時,表中的數據實際上都是存儲在 聚簇索引的葉子節點的。而記錄又是存儲在數據頁中的,數據頁和記錄又是按照記錄 主鍵值從小到大 的順序進行排序,所以如果我們 插入 的記錄的主鍵值是依次增大的話,那我們每插滿一個數據頁就換到下一個數據頁繼續插,而如果我們插入的,主鍵值忽大忽小的話,則可能會造成頁面分裂和記錄移位。
頁面分裂和記錄移位意味著: 性能損耗 !所以如果我們想盡量避免這樣無謂的性能損耗,最好讓插入的記錄的 主鍵值依次遞增 ,這樣就不會發生這樣的性能損耗了。 所以我們建議:讓主鍵具有 AUTO_INCREMENT ,讓存儲引擎自己為表生成主鍵,而不是我們手動插入 。這樣的主鍵占用空間小,順序寫入,減少頁分裂。
4、計算、函數、類型轉換(自動或手動)導致索引失效
在使用計算、函數、類型轉換時,要遍歷全表進行計算、函數、類型轉換得到一個新的結果和條件值進行比較,所以沒有使用索引。
如果給字段name創建了索引,則
#1.索引優化失效
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name,3) = 'abc';
#索引優化生效
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%';
5、類型轉換導致索引失效
如果name是varchar類型,并創建了索引
# 數字默認轉成字符串導致索引失敗
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name=123;
# 索引優化成目標字符串,走索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name='123';
6、范圍條件右邊的列索引失效
例如(name,class_id,age)聯合索引,查詢條件name,class_id,age,如果class_id使用了范圍查詢,那么class_id右邊的age索引失效。這里右邊看的聯合索引的鍵右邊。
解決辦法:新建聯合索引(name,age,class_id)或(age,name,class_id),把需要范圍查詢的字段放在最后。
范圍包括:<、<=、>、>=和 between等。
應用開發中范圍查詢,例如:金額查詢,日期查詢往往都是范圍查詢。應將查詢條件放置where語句最后。創建的聯合索引中,務必把范圍涉及到的字段寫在最后)
7、不等于(!= 或者<>)索引失效
要進行全表掃描
8、is null可以使用索引,is not null無法使用索引
最好在設計數據表的時候就將 字段設置為 NOT NULL 約束 ,比如你可以將INT 類型的字段,默認值設置為 0。將字符類型的默認值設置為空字符串(“”)。
同理,在查詢中使用 not like 也無法使用索引,導致全表掃描。
9、like以通配符%開頭索引失效
在使用LIKE關鍵字進行査詢的査詢語句中,如果匹配字符串的第一個字符為“%”,索引就不會起作用。只有“%”不在第一個位置,索引才會起作用。
【強制】頁面搜索嚴禁左模糊或者全模糊,如果需要請走搜索引擎來解決。
10、OR 前后存在非索引的列,索引失效
在 WHERE 子句中,如果在 OR 前的條件列進行了索引,而在 OR后的條件列沒有進行索引,那么索引會失效。也就是說,OR前后的兩個條件中的列都是索引時,查詢中才使用索引。
因為 OR的含義就是兩個只要滿足一個即可,因此,只有一個條件列進行了索引是沒有意義的,只要有條件列沒有進行索引,就會進行 全表掃描,因此索引的條件列也會失效。
11、數據庫和表的字符集統一使用utf8mb4
統一使用utf8mb4(5.5.3版本以上支持)兼容性更好,統一字符集可以避免由于字符集轉換產生的亂碼。不同的字符集 進行比較前需要進行轉換會造成索引失效。
以下我附上宋紅康老師的視頻教程鏈接供大家詳細學習
數據庫索引失效的11種情況上
數據庫索引失效的11種情況下