索引的基礎概念
索引類似於書籍的目錄,要想找到一本書的某個特定主題,需要先查詢書的目錄,定位對應的頁碼;儲存引擎使用類似的方式進行資料查詢,先去索引當中找到對應的值,然後根據匹配的索引找到對應的資料行
索引對效能的影響
大大減少伺服器需要掃描的資料量、幫助伺服器避免排序和臨時表、將隨機I/O變成順序I/O、大大提高查詢速度,讀寫降低寫的速度(讀寫操作會操作索引)並且佔用磁碟開銷(索引也是資料)
索引的型別
普通索引:最基本的索引,沒有任何約束限制
唯一索引:與普通索引類似,但是具有唯一性索引
主鍵索引:特殊的唯一索引,不允許有空值
唯一索引和主鍵索引的區別:一個表只能有一個主鍵索引,可以有多個唯一索引。主鍵索引一定是唯一索引,唯一索引不是主鍵索引。主鍵可以與外來鍵構成參照完整性約束,防止資料不一致
組合索引:將多個列組合在一起建立索引,可以覆蓋多個列。(比如查詢某本書的第幾個小節,那麼需要建立章和節的索引)
外來鍵索引:只有InnoDB型別的表才可以使用外來鍵索引,保證資料的一致性、完整性和實現級聯操作。
全文索引:Mysql自帶的全文索引只用於MyIsam,並且只能對英文全文檢測
Mysql索引的建立原則
1:最適合索引的列是出現在WHERE子句中的列,或連線子句中的列而不是出現在SELECT關鍵字後的列(比如建立索引的時候,列是WHERE後的列,或者ON後的列)
2:索引列的基數越大,效果越好
3:對字串進行索引,應該制定一個字首長度,可以節省大量的索引空間,不然開銷很大的空間
4:根據情況建立複合索引,複合索引可以提高查詢效率
5:避免過多建立索引,索引會額外佔用磁碟空間,降低寫操作效率
6:主鍵儘可能選擇較短的資料型別,可以有效的減少索引的磁碟佔用提高查詢效率
7:頻繁更新增刪改的欄位\表不要加索引
8:查詢中與其他表關聯的欄位,外間關係建立索引
9:單鍵/組合索引的選擇上,最好選擇組合索引,特別是在高併發環境下
10:查詢中排序的欄位,排序欄位若通過索引去訪問將大大提高排序速度
11:查詢中統計或者分組的欄位(分組就是group by,但是分組的前提是必須排序,也就是分組和索引息息相關)
12:表記錄太少,不需要建索引,起碼300W
13:資料列包含需要重複的內容,不要建,比如性別
Mysql索引的注意事項
1:複合索引遵循字首原則
KEY(a,b,c),一個索引作用在abc三個欄位上,比如書來說,章/節/段/
有效的查詢:/WEHRE a = 1 AND b = 2 AND c = 3/WHERE a = 1 AND b = 2 /WHERE a = 1
無效的查詢:/WHERE b = 2 AND c = 3/WHERE a = 1 AND c = 3
原因:跳過a了,跳過了b,沒有遵循字首原則
2:LIKE查詢,%不能在前,可以使用全文檢索解決
如:WHERE name LIKE '%wang%',即使建立了索引也會失效。
3:column is null 可以使用索引
4:如果Mysql估計使用索引比全表掃描要慢,Mysql會放棄索引的使用
如:表裡有100條資料,語句為 WHERE id > 1 AND id <100,即使對id建立了索引,搜尋的時候需要搜2~99的資料,搜尋的時候回找id為2這條資料,先去索引看一下,找到位置,再去看資料行,再去看3,去看索引,再去看資料行....這樣多了一個查詢索引的步驟。但Mysql認為本身就100條, 你要查詢98條資料,這樣查就很慢了,我直接把100條掃一下直接返回了,比用索引快多了,自動放棄索引,因為Mysql本身具備優化器
5:如果or前的條件中列有索引,後面的沒有,索引都不會被用到
如:WHERE a OR b ,a裡有索引,b裡沒有,那麼索引就會失效了
6:列型別是字串型別,查詢時一定要給值加引號,否則索引失效
如:WHERE name = 'wangteng',加引號才有效;再比如有時候字串的列裡有數字型別的字元,習慣性數字略掉引號,那麼這樣會失效
以聯合索引為例
索引的一些場景
1.選擇唯一性索引
唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄。例如,學生表中學號是具有唯一性的欄位。為該欄位建立唯一性索引可以很快的確定某個學生的資訊。如果使用姓名的話,可能存在同名現象,從而降低查詢速度。
2.為經常需要排序、分組和聯合操作的欄位建立索引
經常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的欄位,排序操作會浪費很多時間。如果為其建立索引,可以有效地避免排序操作。
3.為常作為查詢條件的欄位建立索引
如果某個欄位經常用來做查詢條件,那麼該欄位的查詢速度會影響整個表的查詢速度。因此,為這樣的欄位建立索引,可以提高整個表的查詢速度。
4.限制索引的數目
索引的數目不是越多越好。每個索引都需要佔用磁碟空間,索引越多,需要的磁碟空間就越大。修改表時,對索引的重構和更新很麻煩。越多的索引,會使更新表變得很浪費時間。
5.儘量使用資料量少的索引
如果索引的值很長,那麼查詢的速度會受到影響。例如,對一個CHAR(100)型別的欄位進行全文檢索需要的時間肯定要比對CHAR(10)型別的欄位需要的時間要多。
6.儘量使用字首來索引
如果索引欄位的值很長,最好使用值的字首來索引。例如,TEXT和BLOG型別的欄位,進行全文檢索會很浪費時間。如果只檢索欄位的前面的若干個字元,這樣可以提高檢索速度
7.刪除不再使用或者很少使用的索引
表中的資料被大量更新,或者資料的使用方式被改變後,原有的一些索引可能不再需要。資料庫管理員應當定期找出這些索引,將它們刪除,從而減少索引對更新操作的影響。
8 . 最左字首匹配原則,非常重要的原則。
MySQL會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a 1=”” and=”” b=”2” c=”“> 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
9 .=和in可以亂序。
比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式
10 . 儘量選擇區分度高的列作為索引。
區分度的公式是count(distinct col)/count(*),表示欄位不重複的比例,比例越大我們掃描的記錄數越少,唯一鍵的區分度是1,而一些狀態、性別欄位可能在大資料面前區分度就 是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不同,這個值也很難確定,一般需要join的欄位我們都要求是0.1以上,即平均1條掃描10條 記錄
11 .索引列不能參與計算,保持列“乾淨”。
比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡單,b+樹中存的都是資料表中的欄位值,但進行檢索時,需要把所有元素都應用函式才能比較,顯然成本 太大。所以語句應該寫成create_time = unix_timestamp(’2014-05-29’);
12 .儘量的擴充套件索引,不要新建索引。
比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可
注意:選擇索引的最終目的是為了使查詢的速度變快。上面給出的原則是最基本的準則,但不能拘泥於上面的準則。讀者要在以後的學習和工作中進行不斷的實踐。根據應用的實際情況進行分析和判斷,選擇最合適的索引方式。
索引優化口訣
全值匹配我最愛,最左字首要遵守;
帶頭大哥不能死,中間兄弟不能斷;
索引列上少計算,範圍之後全失效;
LIKE百分寫最右,覆蓋索引不寫星;
不等空值還有OR,索引失效要少用;
VARC引號不能丟,SQL高階也不難;