聚蔟索引緩存
聚蔟索引並非一種單獨的索引類型,而是一種數據存儲方式。Innodb的聚蔟索引在同一結構保存了B-Tree索引和數據行。性能
當表有聚蔟索引時,它的數據行實際上存放在索引的葉子頁中。下圖展現了聚蔟索引中的記錄是如何存放的。注意到,葉子頁包含了行的所有數據,可是節點頁只包含了索引列。測試
彙集的數據有一些重要的優勢:優化
固然,聚蔟索引也有一些缺點:ui
InnoDB和MyISAM的數據分佈對比spa
聚蔟索引和非聚蔟索引的數據分佈有區別,以及對於的主鍵索引和二級索引的數據分別以也有區別。來看看InnoDB和MyISAM是如何存儲下面這個表的:3d
CREATE TABLE layout_test( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2) );
假設該表的主鍵取值1--100001,隨機插入並使用OPTIMIZE TABLE 命令作優化。也就是說,數據在磁盤的存儲方式已經最優,但行的順序是隨機的。列col2的值是從1--100之間隨機賦值,因此有不少重複的值。版本控制
MyISAM的數據分佈比較簡單,以下圖:指針
在行的旁邊顯示了行號,從0遞增,因此MyISAM能夠從表的開頭跳過所需的字節找到所需的行。這種分佈方式很容易建立索引。下面顯示的一系列圖,所以了頁的物理細節,只顯示索引中的「節點」,索引中的每一個葉子節點包含行號。圖一爲主鍵分佈,圖二爲col2索引列分佈code
InnoDB的數據分佈。由於InnoDB支持聚蔟索引,因此用不一樣的方式存儲一樣的數據。下圖爲InnoDB表的主鍵分佈。
聚蔟索引的每個葉子節點都包含了主鍵值,事務ID,用於事務和MVCC(多版本控制)的回滾指針以及全部的剩餘列。
還有一點與MyISAM不一樣的是,InnoDB的二級索引和聚蔟索引很不相同。
這樣作的好處是減小了當出現行移動或者數據頁分裂時二級索引的維護工做。使用主鍵值看成指針會讓二級索引佔用更多的空間,換來的好處是,InnoDB在移動行是無需更新二級索引中的這個「指針」。
下圖是描述InnoDB和MyISAM如何存放表的抽象圖。
在InnoDB表中按主鍵順序插入行
最好避免隨機的聚蔟索引,特別是I/O密集型的應用。例如,從性能的角度考慮,使用UUID來做爲聚蔟索引則會很糟糕,它使得聚蔟索引的插入變得完成隨機。
爲了演示這一點,咱們作以下兩個基準測試。第一個使用整數ID插入userinfo表:
CREATE TABLE userinfo ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(64) NOT NULL DEFAULT '', email varchar(64) NOT NULL DEFAULT '', password varchar(64) NOT NULL DEFAULT '', dob date DEFAULT NULL, address varchar(255) NOT NULL DEFAULT '', city varchar(64) NOT NULL DEFAULT '', state_id tinyint unsigned NOT NULL DEFAULT '0', zip varchar(8) NOT NULL DEFAULT '', country_id smallint unsigned NOT NULL DEFAULT '0', gender enum('M','F') NOT NULL DEFAULT 'M', account_type varchar(32) NOT NULL DEFAULT '', verified tinyint NOT NULL DEFAULT '0', allow_mall tinyint unsigned NOT NULL DEFAULT '0', parrent_account int unsigned NOT NULL DEFAULT '0', closest_airport varchar(3) NOT NULL DEFAULT '', PRIMARY KEY(uuid), UNIQUE KEY email (email), KEY country_id (country_id), KEY state_id (state_id), KEY state_id_2 (state_id,city,address) )ENGINE=InnoDB;
第二個例子是userinfo_uuid表,除了主鍵改成uuid varchar(32),其他和前面的userinfo表徹底相同。
咱們測試這兩個表,先各自向表中插入100萬條數據,而後再插入300萬條數據。
userinfo插入100萬條的時間 (插入時間隨測試機的性能而異,你們看時間差距就好)
userinfo_uuid插入100萬條的時間
userinfo插入300萬條的時間
userinfo_uuid插入300萬條的時間
向UUID主鍵插入行不只花費時間長,並且索引佔用空間更大。這一方面因爲主鍵字段更長,另外一方面毫無疑問是因爲頁分裂和碎片致使。
明白了緣由,咱們來看看第一個表插入數據時,索引起生了什麼變化。下圖顯示了插滿一個頁面後繼續插入相鄰的下一個頁面的場景。
再來看看第二個UUID表的插入有什麼不一樣
能夠看到,在插入UUID表中,移動行的狀況很是頻繁,這樣會增長不少額外的工做,並致使數據分佈不夠優化。下面是總結的一些缺點:
在把這些隨機值載入到聚蔟索引後,也許須要作一次OPTIMIZE TABLE 來重建表並優化頁的填充。
從這個案例能夠看到,使用InnoDB時應儘量按主鍵順序插入數據,而且儘量地使用單調遞增的聚蔟鍵的值來插入新行。