mysql索引使用原則
索引使用的一些原則
(1)表一定要有主鍵,顯式定義主鍵且採用與業務無關的列以避免修改。InnoDB表在有主鍵時會自動將主鍵設為聚集索引,建議採用自增列來使資料順序插入。
(2)關於合理新增索引,有一個通常的法則,即對於經常被查詢的列、經常用於表連線的列、經常排序分組的列,需要建立索引。
(3)建立索引之前,還要檢視索引的選擇性(不重複的索引值和表的記錄總數的比值)來判斷這個欄位是否合適建立索引。索引的選擇性越接近於1,說明選擇性越高,非常適合建立索引。
(4)組合索引(表中兩個或兩個以上的列上建立的索引),一般把選擇性高的列放在前面。組合索引欄位數不建議超過5個,如果5個欄位還不能極大地縮小row範圍,那麼肯定是設計有問題。
(5)合理利用覆蓋索引(只需通過索引就可以返回查詢所需要的資料,不必在查到索引之後再回表查詢資料)。禁止使用select *,只獲取必要欄位,指定欄位能有效利用索引覆蓋。
(6)使用explain判斷SQL語句是否合理使用了索引,儘量避免Extra列出現Using File Sort、Using Temporary。
(7)單張表的索引數量建議控制在5個以內,索引太多也會浪費空間且降低修改資料的速度,影響效能。
(8)不建議在頻繁更新的欄位上建立索引。
(9)Where條件中的索引列不能是表示式的一部分,避免在Where條件中在索引列上進行計算或使用函式,因為這將導致索引不被使用而進行全表掃描。
(10)如果要進行join查詢,那麼被join的欄位必須型別相同並建立索引,因為join欄位型別不一致會導致全表掃描。
(11)隱式型別轉換會使索引失效,導致全表掃描。
以下演示違反索引使用規則的情形,會導致全表掃描。
(1)案例一:在表tt1中,給欄位log_time增加了索引,如圖4-28所示。
通過explain檢視查詢SELECT * FROM t1 WHERE DATE(log_time)='2015-04-09'的執行計劃,如圖4-29所示。我們發現type列是ALL,這條語句進行了一個全表掃描。雖然給欄位log_time加了索引,但是沒有用到索引,因為違背避免在Where條件中在索引列上進行計算或使用函式。在MySQL裡,一般修改為SELECT * FROM t1 WHERE log_time >= '2015-04-09 00:00:00' AND log_time <= '2015-04-10 00:00:00',通過explain檢視查詢執行計劃時使用到了索引。MySQL 5.7的虛擬列(Generated Columns)特性實現表示式索引,就是用來解決這個問題的。可以增加一個可被索引的列,但實際上並不存在於資料表中。可以對log_time建立一個虛擬列,然後對虛擬列建立索引,但是後期會增加運維人員的運維難度。
(2)案例二:在表test_2中,SQL語句非常簡單,就是“select id,user_id,name from test_1 where user_id=1”這種型別,而且user_id上已經建立索引,查詢還是很慢,如下圖所示,利用explain檢視語句執行計劃,發現進行了全表掃描,type列還是ALL,並沒有用上user_id的索引。
認真觀察一下表結構,user_id的欄位型別是字串,而使用者傳入的是int,這裡會有一個隱式轉換的問題。隱式型別轉換會使索引失效,導致全表掃描。把輸入改成字串型別,檢視執行計劃“explain select id, user_id, name from test_2 where user_id='1'”,就會用到索引