【MySQl】MyISAM和InnoDB索引對比

部份內容轉自:http://www.2cto.com/database/201211/172380.htmlhtml

比較好的文章:http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.htmlmysql

MyISAM算法

MyISAM引擎使用B+Tree做爲索引結構,葉節點的data域存放的是數據記錄的地址。下圖是MyISAM索引的原理圖:sql

這裏設表一共有三列,假設咱們以Col1爲主鍵,則上圖是一個MyISAM表的主索引(Primary key)示意。能夠看出MyISAM的索引文件僅僅保存數據記錄的地址。在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複。若是咱們在Col2上創建一個輔助索引,則此索引的結構以下圖所示:優化

 

一樣也是一顆B+Tree,data域保存數據記錄的地址。所以,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,則取出其data域的值,而後以data域的值爲地址,讀取相應數據記錄。
MyISAM的索引方式也叫作「非彙集」的,之因此這麼稱呼是爲了與InnoDB的彙集索引區分。
 
InnoDB
雖然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭。
第一個重大區別是InnoDB的數據文件自己就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。
上圖是InnoDB主索引(同時也是數據文件)的示意圖,能夠看到葉節點包含了完整的數據記錄。這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL 系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列, 則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。

第二個與MyISAM索引的不一樣是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域。例如,下圖爲定義在Col3上的一個輔助索引:
這裏以英文字符的ASCII碼做爲比較準則。彙集索引這種實現方式使得按主鍵的搜索十分高效,可是輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄。

瞭解不一樣存儲引擎的索引實現方式對於正確使用和優化索引都很是有幫助,例如知道了InnoDB的索引實現後,就很容易明白爲何不建議使用過長的字段做爲主鍵, 由於全部輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如, 用非單調的字段做爲主鍵在InnoDB中不是個好主意由於InnoDB數據文件自己是一顆B+Tree,非單調的主鍵會形成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段做爲主鍵則是一個很好的選擇。
 
聯合索引或者叫作複合索引、組合索引,在《MySQL技術內幕InnoDB存儲引擎》的‘5.6.4聯合索引’章節有一些描述(第二版內容無更新),是指對錶上的多個列作索引,聯合索引也是一顆B+樹,聯合索引的鍵值的數量不是1,而是大於等於2,show index以下:
mysql> show create table t2;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                    |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `column_a` int(11) DEFAULT NULL,
  `column_b` int(11) DEFAULT NULL,
  `column_c` int(11) DEFAULT NULL,
  `column_d` varchar(10) DEFAULT NULL,
  KEY `index_a_b_c` (`column_a`,`column_b`,`column_c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show index  from t2 \G
*************************** 1. row ***************************
        Table: t2
   Non_unique: 1
     Key_name: index_a_b_c
 Seq_in_index: 1
  Column_name: column_a
    Collation: A
  Cardinality: 9
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
*************************** 2. row ***************************
        Table: t2
   Non_unique: 1
     Key_name: index_a_b_c
 Seq_in_index: 2
  Column_name: column_b
    Collation: A
  Cardinality: 9
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
*************************** 3. row ***************************
        Table: t2
   Non_unique: 1
     Key_name: index_a_b_c
 Seq_in_index: 3
  Column_name: column_c
    Collation: A
  Cardinality: 9
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
3 rows in set (0.00 sec)

mysql> select count(*) from t2;
+----------+
| count(*) |
+----------+
|        9 |
+----------+
1 row in set (0.01 sec)

show index語法的說明:spa

1Table:索引所在的表名。
2、Non_unique:非惟一的索引,能夠看到primary key是0,由於必須是惟一的。
3、Key_name:索引的名稱,我們能夠經過這個名稱來drop index。
4、Seq_in_index:索引中該列的位置,若是看聯合索引就比較直觀。(例如上面例子)
5、Column_name:索引的列。
6、Collation:列以什麼方式存儲在索引中。能夠是‘A’或者NULL。B+樹索引老是A,即排序的。若是使用了Heap存儲索引,而且創建了Hash索引,這裏就會顯示NULL。由於Hash根據Hash桶來存放索引數據,而不是對數據進行排序。
7、Cardinality:很是關鍵的值,表示索引中惟一值得數目的估計值,優化器會根據這個值來判斷查詢是否使用這個索引。Cardinality/表的行數的比值應儘量接近1,若是很是小,那麼須要考慮是否還須要建這個索引。這個值不是實時更新的,由於開銷會很大,能夠經過運行ANALYZE TABLE或myisamchk -a能夠更新這個值。
8、Sub_part:是不是列的部分被索引。假設若是看index_a這個索引,這裏顯示10,表示只索引a列的前10個字符。若是索引整個列,則該字段爲NULL。
9、Packed:關鍵字如何被壓縮。若是沒有被壓縮,則爲NULL。
10Null:是否索引的列含有NULL值。能夠看到index_a_b_c這裏爲YES,由於咱們定義的a、b、c列容許NULL值。
11、Index_type:索引的類型。InnoDB存儲引擎只支持B+樹索引,因此這裏顯示的都是BTREE。
12、Comment:註釋。

聯合索引形象的說明能夠比喻成手機中的電話薄,由於聯合索引是多個鍵值的B+樹狀況,和單列索引的鍵值順序排序相同,使用聯合索引也是經過葉節點邏輯上的順序地讀出全部數據,好比表中column1和column2要建一個index_1_2,那這個聯合索引會先按照column1順序存放,在column1值相同的數據,再使用coiumn2順序存放。例如:(1,1),(1,2),(2,1),(2,4),(3,1),(3,2),按照(column1,column2)的順序進行存放:3d

 
聯合索引也能夠認爲是多列組成的輔助索引,一樣引用主鍵做爲data域。
另外聯合索引的使用一樣須要掌握好規律,如最開始的index_a_b_c這個組合索引,真正可以使用到索引的是:
mysql> explain select * from t2 where column_a=1 and column_b=2 and column_c=3;
+----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
| id | select_type | table | type | possible_keys | key         | key_len | ref               | rows | Extra       |
+----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
|  1 | SIMPLE      | t2    | ref  | index_a_b_c   | index_a_b_c | 15      | const,const,const |    1 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from t2 where column_a=1 and column_b=2;
+----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key         | key_len | ref         | rows | Extra       |
+----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
|  1 | SIMPLE      | t2    | ref  | index_a_b_c   | index_a_b_c | 10      | const,const |    1 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from t2 where column_a=1;
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key         | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      | t2    | ref  | index_a_b_c   | index_a_b_c | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

另外針對column_a和column_c兩列的查詢,實際上只是用到了組合索引中的column_a部分:code

mysql> explain select * from t2 where column_a=1 and column_c=3;               
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key         | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      | t2    | ref  | index_a_b_c   | index_a_b_c | 5       | const |    2 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

能夠看到key_len是5,查詢經過索引index_a_b_c的column_a中找到相應column_a=1行的葉子節點邏輯位置區域,可是因爲條件column_c沒法被使用到索引,遍歷了column_a=1的全部行。htm

因此你們習慣說的聯合索引的"最左前綴"的原則,簡單的理解就是隻從聯合索引組合的最左側的列開始的組合順序組合。blog

理解了聯合索引機制,什麼用不到就更好理解:

mysql> explain select * from t2 where column_b=2 and column_c=3;  
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t2    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from t2 where column_b=2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t2    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from t2 where column_c=3;               
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t2    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
相關文章
相關標籤/搜索