MySQL索引優化和組合索引
幾乎所有的面試都提到了Mysql的優化問題,所以以后要多多學習數據庫的優化知識了。下面僅僅考慮在索引方面的優化,此處的索引包括多列索引和聯合索引!下邊是在網上找到的一些資料,保留下來備用吧。
一 什么是索引
MySQL中,索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含著對數據表里所有記錄的引用指針。索引按照實現的方式有不同的種類,像B-Tree索引,hash索引,空間數據索引和全文索引等。下面分析B-Tree索引。
1) 索引定義
普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任務是加快對數據的訪問速度。普通索引允許被索引的數據列包含重復的值。如果能確定某個數據列將只包含彼此各不相同的值,在為這個數據列創建索引的時候就應該用關鍵字UNIQUE把它定義為一個唯一索引。也就是說,唯一索引可以保證數據記錄的唯一性。
主鍵,是一種特殊的唯一索引,在一張表中只能定義一個主鍵索引,用于唯一標識一條記錄,使用關鍵字 PRIMARY KEY 來創建。
索引可以覆蓋多個數據列,如像INDEX(columnA, columnB)索引,這就是聯合索引。
索引可以極大的提高數據的查詢速度,但是會降低插入、刪除、更新表的速度,因為在執行這些寫操作時,還要操作索引文件。
2) 創建索引
在where,order by,group by中頻繁出現,且數據分布比較離散的列適合創建索引。
很多時候一些簡單的性能問題是因為忘了添加索引而造成的,或者說沒有添加更為有效的索引導致的。如果不加索引,那么查找任何哪怕只是一條特定的數據都會進行一次全表掃描,如果一張表的數據量很大而符合條件的結果又很少,那么不加索引會引起致命的性能問題——慢得如蝸牛。但是也不是什么情況都非得建索引不可,值可以枚舉的字段就無需創建索引,比如性別,因為只有男,女,未知等幾種,數據不夠離散,建索引顯然是畫蛇添足。
頻繁修改的列不適合創建索引。索引基于B+樹實現,修改數據時,需要修改對應的索引。因此不適合創建索引
3) 不使用NOT IN操作
NOT IN操作都不會使用索引將進行全表掃描。NOT IN可以由NOT EXISTS代替。
4) 索引不可包含有NULL值的列
這個問題有點復雜,盡量回避。
null列是可以用到索引的,不管是單列索引還是聯合索引,但是,不建議這么操作,最好限制not null,并設置一個默認值,比如0和''空字符串等。官方文檔中介紹到,如果某列字段中包含null,確實是可以使用索引的,地址:https://dev.mysql.com/doc/refman/5.7/en/is-null-optimization.html。
5) 使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10 個或20 個字符內,多數值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。
6) 排序的索引問題
mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那么order by中的列是不會使用索引的。因此,在數據庫默認排序已經符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建復合索引。
7) like語句操作
一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。
8) 不要在列上進行運算
select * from users where YEAR(adddate)<2007;
此SQL將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成 select * from users where adddate<‘2007-01-01’;
下面綜述哪些操作符可以命中索引,哪些不可以。
能命中索引: <,<=,=,>,>=,BETWEEN,IN, like 'xx%';
不能命中: <>,not in ,!=,like '%xx'。
二 多列索引
多個單列索引在多條件查詢時只會生效距離where最近的那索引!所以多條件聯合查詢時最好建聯合索引!假設users中age和area分別創建了索引,則如下SQL中,例1只有area走索引,例2只有age走索引。
例1 select * from users where area=’beijing’ and age=22;
例2 select * from users where age=22 and area=’beijing’;
但是,如果把and換為or,則兩個索引都走了。
三 復合索引
復合索引的結構與電話簿類似,人名由姓和名構成,電話簿首先按姓氏排序,然后按名字對有相同姓氏的人排序。如果知道姓,電話簿將非常有用;如果知道姓和名,電話簿則更為有用,但如果只知道名,電話簿幾乎不起作用了。所以說創建復合索引時,應該仔細考慮列的順序。
如果在表users創建了復合索引(area, age, salary),那么其實相當于創建了(area,age,salary)、(area,age)、(area)三個索引,這被稱為最左前綴原則,顧名思義,就是最左優先。因此我們在創建復合索引時應該將最常用作限制條件的列放在最左邊,依次遞減。
另外,(area, salary)中,只有area走索引。
復合索引是常考的點,小伙伴們,記牢呦。 下面從網上摘抄了一個表格,信息量比較大,僅供參考!以 index(a, b, c) 為例:
|
WHERE 語 句 |
發揮作用的索引 |
記憶方法(以三塊板子過河記憶,順序很重要) |
|
WHERE a=3 |
a |
只走了a板子 |
|
WHERE a=3 AND b=5 |
a、b |
只走了ab兩塊板子 |
|
WHERE a=3 AND b=4 AND c=5(不論順序) |
a、b、c |
走了所有的板子 |
|
WHERE b=4 AND c=5 或 WHERE b=4 |
無 |
因為a板子沒走,所以銜接不上b和c板子 |
|
WHERE a=3 AND c=5 |
a |
只走a,沒走b就銜接不上c |
|
WHERE a=3 AND b>10 AND c=7 |
a、b |
走完了a,但b走了一半,與c銜接不上了 |
|
WHERE a=3 AND b LIKE '***%' AND c=7 |
a、b |
走完了a,b走了前一半,與c銜接不上了 |
|
WHERE a=3 AND b LIKE '%***' AND c=7 |
a |
走完了a,b走了后一半,但b前半段與a銜接不上了,走也是白走 |
|
WHERE a=3 AND c>10 AND b=4 |
a、b、c |
走完了a和b,c只走了一半 |
注意:1)例子里都是 WHERE 語句,但 ORDER BY/GROUP BY 等都會用到索引,分析與上面一樣
2)MySQL會一直向右匹配,直到查詢中遇到范圍查詢(<、>、between、like和%)等就停止匹配后面的查詢條件
聯合索引比對每個列分別建索引更有優勢,因為索引建立得越多就越占磁盤空間,在更新或者寫入數據的時候需要進行IO操作,從而導致速度下降。另外建立多列索引時,順序也是需要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高。
Buy me a coffee. ?Get red packets.
浙公網安備 33010602011771號