MySQL中每一個表都有一個聚簇索引( clustered index ),除此以外的表上的每一個非聚簇索引都是二級索引,又叫輔助索引( secondary indexes )。以InnoDB來講,每一個InnoDB表具備一個特殊的索引稱爲彙集索引。若是表上定義有主鍵,那麼該主鍵索引是彙集索引。若是表中沒有定義主鍵,那麼MySQL取第一個惟一索引( unique )並且只含非空列( NOT NULL )做爲主鍵,InnoDB使用它做爲彙集索引。若是沒有這樣的列,InnoDB就本身產生一個這樣的ID值,它有六個字節,並且是隱藏的,使其做爲聚簇索引。html
0x01:聚簇索引,提及索引,不能不說B+樹mysql
http://blog.codinglabs.org/articles/theory-of-mysql-index.html
MySQL官方索引的定義:索引( Index )是幫助MySQL高效獲取數據的數據結構。提取句子主幹,就能夠獲得索引的本質;索引是數據結構。算法
數據庫查詢是數據庫的最主要功能之一。誰都但願查詢數據的速度能儘量的快,所以數據庫系統的設計者會從查詢算法的角度進行優化。最基本的查詢算法固然是順序查找( linear search ),這種複雜度爲O(n)的算法在數據量很大時顯然是糟糕的,好在計算機科學的發展提供了不少更優秀的查找算法,例如二分查找(binary search),二叉樹查找(binary tree search)等。若是稍微分析一下會發現,每種查找算法都只能應用於特定的數據結構之上,例如二分查找要求被檢索數據有序,而二叉樹查找只能應用於二叉查找樹上,可是數據自己的組織結構不可能徹底知足各類數據結構(例如,理論上不可能同時將兩列都按順序進行組織),因此在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。sql
聚簇索引並非一種單獨的索引類型,而是一種數據存儲方式。具體的細節依賴於其實現方式,但InnoDB的聚簇索引實際上在同一個結構中保存了B-Tree索引和數據行。數據庫
當表有聚簇索引時,他的數據行實際上存放在索引的葉子頁(leaf page)中。術語 「聚簇」表示數據行和相鄰的鍵值緊湊地存儲在一塊兒(這並不是總成立)。由於沒法同時把數據行存放在兩個不一樣的地方,索引一個表只能有一個聚簇索引。數據結構
0x02:聚族索引的優勢ide
能夠把相關數據保存在一塊兒。例如實現電子郵件時,能夠根據用戶ID來彙集數據,這樣只須要從磁盤讀取少數的數據頁就能獲取某個用戶的所有郵件。若是沒有使用聚族索引,則每封郵件均可能致使一次磁盤I/O;性能
數據訪問更快。聚族索引將索引和數據保存在同一個B-Tree中,所以從聚族索引中獲取數據一般比在非聚族索引中查找更快。優化
使用覆蓋索引掃描的查詢能夠直接使用節點中的主鍵值。設計
0x03:聚族索引的缺點
聚簇數據最大限度的提升了I/O密集型應用的性能,但若是數據所有都放在內存中,則訪問的順序就沒有那麼重要了,聚簇索引也就沒有那麼優點了;
插入速度嚴重依賴於插入順序。按照主鍵的順序插入是加載數據到InnoDB表中速度最快的方式。但若是不是按照主鍵順序加載數據,那麼在加載完成後最好使用OPTIMIZE TABLE命令從新組織一下表。
更新聚簇索引列的代價很高,由於會強制InnoDB將每一個被更新的行移動到新的位置。
基於聚簇索引的表在插入新行,或者主鍵被更新致使須要移動行的時候,可能面臨「頁分裂」的問題。當行的主鍵值要求必須將這一行插入到某個已滿的頁中時,存儲引擎會將該頁分裂成兩個頁面來容納該行,這就是一次分裂操做。頁分裂會致使表佔用更多的磁盤空間。
聚簇索引可能致使全表掃描變慢,尤爲是行比較稀疏,或者因爲頁分裂致使數據存儲不連續的時候。
二級索引(非聚簇索引)可能比想象的要更大,由於在二級索引的葉子節點包含了引用行的主鍵列。
二級索引訪問須要兩次索引查找,而不是一次。
有關二級索引須要兩次索引查找的問題?
答案在於二級索引中保存的「行指針」的實質。要記住,二級索引葉子節點保存的不是指向行的物理位置的指針,而是行的主鍵值。這意味着經過二級索引查找行,存儲引擎須要找到二級索引的葉子節點得到對應的主鍵值,而後根據這個值去聚簇索引中查找到對應的行。這裏作了重複的工做:兩次B-Tree查找而不是一次。對於InnoDB,自適應哈希索引可以減小這樣的重複工做。