讓咱們先看看下面的這段MySQL代碼:mysql
mysql> SELECT id FROM user WHERE id + 1 = 2;
咱們會發現,在上面這段SQL查詢語句中,咱們給的條件是一個有變量的表達式,若是咱們此時的id列上是存在索引的,那上面的語句能不能使用到索引呢?
答案是不能的,由於MySQL沒法自動的解析 id + 1 = 2 這個條件語句,儘管咱們能夠一眼的看出來此時等價於 id = 1,可是這種作法是沒法使用到索引的,所以咱們在查詢的時候,應該使得索引列不能是表達式的一部分,也不能是函數的參數。程序員
若是咱們須要在某一列,例如存放url的一列數據上添加索引來加快查詢的速度,咱們先看看url數據的特色,長,相似的還有TEXT類型的數據等,這些都是一些很長,佔據很大空間的數據,並且會使得對應的索引大且慢。這時候咱們可使用一些優化的索引策略,例如前綴索引。前綴索引與通常的索引不一樣,他在查詢的時候並不會比對該列數據的全部值,而只是比對它的前面的一部分數據。這樣會使得索引變得更加靈活有效率,可是卻下降了索引選擇性。
什麼是索引選擇性呢?咱們給定一個公示:
索引選擇性 = 不一樣的索引值 / 數據表的記錄總數
首先思考,爲何會有所謂的不一樣索引值和相同的索引值?這都要創建在咱們是使用前綴索引這種方式創建索引的基礎上。例若有兩個數據,「abcalkjsdhgasdfasdf」和「abcalaasdasdqwe」。很顯然這兩個數據是大相徑庭的,可是若是咱們規定前綴索引的長度是數據的前五個字符,那麼會發現這兩個數據的索引值都是「abcal」,即這兩個數據的索引值是同樣的。所以也就下降了索引選擇性。簡單來講,索引選擇性越高,咱們經過索引值能查找到惟一的數據的可能性就越大,索引選擇性越低,咱們經過索引值能查找到的惟一的數據的可能性就越小。那麼這是否就意味着前綴索引是一個不好的選擇呢?並不,由於通常狀況下使用恰當的前綴索引,也是能夠準確的進行數據的查詢,而且可以節省空間的,並且對於BLOB,TEXT或者很長的VARCHAR類型的列,必須使用前綴索引,由於MySQL不容許索引這些列的完整長度。sql
首先,若是一個數據表有3個列,那麼咱們爲每個列都單獨的建立一個索引,是否是就可以使得在查詢的時候,不管進行怎樣的查找,咱們都能得到最快的效率呢?進行下面的表格創建語句:函數
mysql> CREATE TABLE temp (c1 INTEGER,c2 INTEGER,KEY (c1),KEY (c2));
事實證實,在實際的操做中,這種爲每個列都創建一個索引的「單純」的想法,對查找的效率提高很是的有限,與最佳的索引方案每每效率差距了幾個量級。
在MySQL5.0以後的版本多出了「索引合併」的策略,必定程度上是幫程序員優化了這種在一個數據表上建立許多單列索引的操做,可是仍是不建議使用這種索引策略。在MySQL5.0以前的版本,若是咱們爲表film_actor的字段film_id和actor_id分別建立一個單列索引,而後執行如下的查詢操做:性能
mysql> SELECT film_id, actor_id FROM film_actor WHERE film_id = 1 OR actor_id = 1;
事實上,在這個查詢語句中,咱們所定義的兩個單列索引都沒法幫忙提升效率,甚至於在老版本的MySQL中,將會使用全表掃描來完成這個查詢,這就使得這個索引策略變得徹底沒有意義。
除非將上面的語句改寫成如下的形式:優化
mysql> SELECT actor_id, film_id FROM film_actor WHERE actor_id = 1 UNION ALL SELECT actor_id, film_id FROM film_actor WHERE film_id = 1
即將查詢改寫成兩個查詢的交集,即每一個查詢都只是用一個列做爲判斷的條件,拿着整MySQL就會很天然的運用這個列的索引。url
所以咱們仍是建議在須要在多個列上創建索引的時候不要單獨的給每一個列創建一個索引,而是選擇創建一個多列索引。spa
mysql> CREATE TABLE temp (c1 INTEGER,c2 INTEGER,KEY (c1, c2));
這個時候選擇一個合適的索引列順序就顯得很是重要了,由於咱們知道,若是咱們使用默認的B-Tree創建一個多列索引的話,MySQL會按照咱們建立時候指定的順序創建索引,即先排c1,再在c1排列好的基礎上排列c2。
並且查詢的時候每次都是從左開始掃描,意味着若是你第一個查詢的列並非索引的最左列,那這個索引對於你來講就形同虛設。
咱們看看以下的一個查詢語句:指針
mysql> SELECT * FROM payment WHERE staff_id = 2 AND customer_id = 584;
那咱們是應該創建一個(staff_id, customer_id)的多列索引仍是將他們的順序顛倒過來呢?咱們能夠先看看這兩個條件的數據量有多大:code
sum(staff_id = 2) = 7992 sum(customer_id = 584) = 30
根據經驗,咱們應該將索引列customer_id 放到前面,由於對應條件值的數據量更小。所以如何選擇索引列的順序仍是應該根據具體的狀況來肯定,沒有惟一的準則。
聚簇索引其實只是一種特殊的B-Tree索引,他並非一種區別於其餘索引的單獨的索引形式,而是一種存儲方式。
當使用聚簇索引的時候,全部的數據都存儲在索引樹的葉子節點上。
下圖展現了聚簇索引中的記錄是如何存放的:
在建立聚簇索引時,InnoDB使用主鍵做爲索引列彙集數據。若是數據表沒有定義主鍵,則會選擇一個惟一的非空索引代替,若是沒有這樣的索引InnoDB則會隱式定義一個主鍵來做爲聚簇索引。
聚簇索引有如下的優勢:
同時,聚簇索引也有如下的缺陷:
因爲聚簇索引的內容比較多,會專門出一篇來較爲深刻的將聚簇索引。