部分内容转自:http://www.2cto.com/database/201211/172380.html

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

MyISAM

MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:

这里设表一共有三列,假设我们以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语法的说明:

1、Table:索引所在的表名。
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。
10、Null:是否索引的列含有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)的顺序进行存放:

 
联合索引也可以认为是多列组成的辅助索引,同样引用主键作为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部分:

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的所有行。

所以大家习惯说的联合索引的"最左前缀"的原则,简单的理解就是只从联合索引组合的最左侧的列开始的组合顺序组合。

理解了联合索引机制,什么用不到就更好理解:

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)

【MySQl】MyISAM和InnoDB索引对比的更多相关文章

  1. 深入浅出分析MySQL MyISAM与INNODB索引原理、优缺点、主程面试常问问题详解

    本文浅显的分析了MySQL索引的原理及针对主程面试的一些问题,对各种资料进行了分析总结,分享给大家,希望祝大家早上走上属于自己的"成金之路". 学习知识最好的方式是带着问题去研究所 ...

  2. 深入浅出分析MySQL MyISAM与INNODB索引原理、优缺点分析

    本文浅显的分析了MySQL索引的原理及针对主程面试的一些问题,对各种资料进行了分析总结,分享给大家,希望祝大家早上走上属于自己的"成金之路". 学习知识最好的方式是带着问题去研究所 ...

  3. mysql myisam转innodb的2种方法

      mysql myisam转innodb的2种方法 mysql中的myisam和innodb有什么区别.一个好比便利店,一个好比大型购物中心,他们是为了适应不同的场合而存在的.当流量比较小,我们可以 ...

  4. mysql常用的存储引擎,MyISAM和InnoDB的对比

    Mysql有多种存储引擎,最常用的有MyISAM和InnoDB这两种,每一种类型的存储引擎都有自已的特点,可以结合项目中数据的使用场景来进行了哪种存储引擎合适. 1:查看mysql数据库支持的存储引擎 ...

  5. MYSQL MyISAM与InnoDB对比

    1. 区别: (1)事务处理: MyISAM是非事务安全型的,而InnoDB是事务安全型的(支持事务处理等高级处理): (2)锁机制不同: MyISAM是表级锁,而InnoDB是行级锁: (3)sel ...

  6. MySQL存储引擎 -- MyISAM 与 InnoDB 理论对比

    MySQL常用的两种存储引擎一个是MyISAM,另一个是InnoDB.两种存储引擎各有各的特点. 1. 区别:(1)事务处理:MyISAM是非事务安全型的.-----而非事务型的系统,一般也称为数据仓 ...

  7. MyISAM和InnoDB索引实现对比

    MyISAM索引实现 MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址.如图:  这里设表一共有三列,假设我们以Col1为主键,则上图是一个MyISAM表的主索引 ...

  8. MyISAM和InnoDB索引区别

    MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址.下图是MyISAM索引的原理图: 图8 这里设表一共有三列,假设我们以Col1为主键,则图8是一个MyISAM表 ...

  9. MySql MyISAM和InnoDB的区别

    MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的 顺序访问方法) 的缩写,它是存储记录和文件的标准方法. ...

随机推荐

  1. c++101rule

    组织策略0,不拘于小结缩进, 行的长度,命名,注释,空格,制表,1-4,高警告级别干净利落地进行编译,使用构建系统,使用版本控制,代码审查风格5,一个实体应该只有一个紧凑的职责. (依赖性管理,继承, ...

  2. AP_AP系列 - 付款管理分析(案例)

    2014-07-08 Created By BaoXinjian 一.摘要 1. 付款 2. 发票付款概述 3. 使用发票工作台付款 4. 使用付款管理器付款 5. 银行账户模型 二.流程分析 1. ...

  3. ubuntu 16.04 小键盘数字键盘开机自动启动

    ubuntu 16.04 小键盘数字键盘开机自动启动 最近安了ubuntu 16.04,用windows用久了,换一个也挺好玩的! 但ubuntu 16.04因为算是最新的吧,还是存在些令我们不适应的 ...

  4. Python分布式爬虫原理

    转载 permike 原文 Python分布式爬虫原理 首先,我们先来看看,如果是人正常的行为,是如何获取网页内容的. (1)打开浏览器,输入URL,打开源网页 (2)选取我们想要的内容,包括标题,作 ...

  5. VMWare虚拟机下RedHat 9.0linux的网络设置

    VMWare虚拟机下安装的RedHat 9.0 linux有三种方式实现上网,桥接.nat.host-only.本来想用桥接方式的,可总是因为配置网络出现问题而不能上网,还把 sygate4.5(代理 ...

  6. 帝国CMS常见问题记录

    1.第一次安装,为什么找不到"增加信息"的地方?因为你未增加栏目,请先增加栏目,然后再增加信息(终极栏目下方可增加信息). 2.为什么信息管理的"信息栏目"列表不变?缓存问题,解决方法如下两种:1." ...

  7. iOS8 StoryBoard 连线diss方法

    添加自定义Dismiss类: //  Dismiss.h //  StoryBoardTest // //  Created by zhujin on 14/12/23. //  Copyright ...

  8. 区分DPI、分辨率(PPI)、图像的物理大小、像素宽度

    分辨率都知道,越高越清晰. 一.描述分辨率的单位有:    dpi(点每英寸).lpi(线每英寸)和ppi(像素每英寸).但只有lpi是描述光学分辨率的尺度的.虽然dpi和ppi也属于分辨率范畴内的单 ...

  9. Mac OS X安装Redis

    http://my.oschina.net/jackieyeah/blog/524583

  10. 加载网络映射盘中的assembly失败

    我有一个网络映射盘,盘符是Z:.在Z盘下面,放了一个assembly,名为test.dll.然后,我在VS2010中建立了一个.NET 4.0的工程,程序中有下面一段代码: string dll = ...