部分内容转自: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如下:
  1. mysql> show create table t2;
  2. +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  3. | Table | Create Table |
  4. +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  5. | t2 | CREATE TABLE `t2` (
  6. `column_a` int(11) DEFAULT NULL,
  7. `column_b` int(11) DEFAULT NULL,
  8. `column_c` int(11) DEFAULT NULL,
  9. `column_d` varchar(10) DEFAULT NULL,
  10. KEY `index_a_b_c` (`column_a`,`column_b`,`column_c`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
  12. +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  13. 1 row in set (0.00 sec)
  14.  
  15. mysql> show index from t2 \G
  16. *************************** 1. row ***************************
  17. Table: t2
  18. Non_unique: 1
  19. Key_name: index_a_b_c
  20. Seq_in_index: 1
  21. Column_name: column_a
  22. Collation: A
  23. Cardinality: 9
  24. Sub_part: NULL
  25. Packed: NULL
  26. Null: YES
  27. Index_type: BTREE
  28. Comment:
  29. Index_comment:
  30. *************************** 2. row ***************************
  31. Table: t2
  32. Non_unique: 1
  33. Key_name: index_a_b_c
  34. Seq_in_index: 2
  35. Column_name: column_b
  36. Collation: A
  37. Cardinality: 9
  38. Sub_part: NULL
  39. Packed: NULL
  40. Null: YES
  41. Index_type: BTREE
  42. Comment:
  43. Index_comment:
  44. *************************** 3. row ***************************
  45. Table: t2
  46. Non_unique: 1
  47. Key_name: index_a_b_c
  48. Seq_in_index: 3
  49. Column_name: column_c
  50. Collation: A
  51. Cardinality: 9
  52. Sub_part: NULL
  53. Packed: NULL
  54. Null: YES
  55. Index_type: BTREE
  56. Comment:
  57. Index_comment:
  58. 3 rows in set (0.00 sec)
  59.  
  60. mysql> select count(*) from t2;
  61. +----------+
  62. | count(*) |
  63. +----------+
  64. | 9 |
  65. +----------+
  66. 1 row in set (0.01 sec)

show index语法的说明:

  1. 1Table:索引所在的表名。
  2. 2Non_unique:非唯一的索引,可以看到primary key0,因为必须是唯一的。
  3. 3Key_name:索引的名称,我们可以通过这个名称来drop index
  4. 4Seq_in_index:索引中该列的位置,如果看联合索引就比较直观。(例如上面例子)
  5. 5Column_name:索引的列。
  6. 6Collation:列以什么方式存储在索引中。可以是‘A’或者NULLB+树索引总是A,即排序的。如果使用了Heap存储索引,并且建立了Hash索引,这里就会显示NULL。因为Hash根据Hash桶来存放索引数据,而不是对数据进行排序。
  7. 7Cardinality:非常关键的值,表示索引中唯一值得数目的估计值,优化器会根据这个值来判断查询是否使用这个索引。Cardinality/表的行数的比值应尽可能接近1,如果非常小,那么需要考虑是否还需要建这个索引。这个值不是实时更新的,因为开销会很大,可以通过运行ANALYZE TABLEmyisamchk -a可以更新这个值。
  8. 8Sub_part:是否是列的部分被索引。假设如果看index_a这个索引,这里显示10,表示只索引a列的前10个字符。如果索引整个列,则该字段为NULL
  9. 9Packed:关键字如何被压缩。如果没有被压缩,则为NULL
  10. 10Null:是否索引的列含有NULL值。可以看到index_a_b_c这里为YES,因为我们定义的abc列允许NULL值。
  11. 11Index_type:索引的类型。InnoDB存储引擎只支持B+树索引,所以这里显示的都是BTREE
  12. 12Comment:注释。

联合索引形象的说明可以比喻成手机中的电话薄,因为联合索引是多个键值的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这个组合索引,真正能够使用到索引的是:
  1. mysql> explain select * from t2 where column_a=1 and column_b=2 and column_c=3;
  2. +----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
  5. | 1 | SIMPLE | t2 | ref | index_a_b_c | index_a_b_c | 15 | const,const,const | 1 | Using where |
  6. +----+-------------+-------+------+---------------+-------------+---------+-------------------+------+-------------+
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> explain select * from t2 where column_a=1 and column_b=2;
  10. +----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  12. +----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
  13. | 1 | SIMPLE | t2 | ref | index_a_b_c | index_a_b_c | 10 | const,const | 1 | Using where |
  14. +----+-------------+-------+------+---------------+-------------+---------+-------------+------+-------------+
  15. 1 row in set (0.00 sec)
  16.  
  17. mysql> explain select * from t2 where column_a=1;
  18. +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
  19. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  20. +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
  21. | 1 | SIMPLE | t2 | ref | index_a_b_c | index_a_b_c | 5 | const | 1 | Using where |
  22. +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
  23. 1 row in set (0.00 sec)

另外针对column_a和column_c两列的查询,实际上只是用到了组合索引中的column_a部分:

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

可以看到key_len是5,查询通过索引index_a_b_c的column_a中找到相应column_a=1行的叶子节点逻辑位置区域,但是由于条件column_c无法被使用到索引,遍历了column_a=1的所有行。

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

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

  1. mysql> explain select * from t2 where column_b=2 and column_c=3;
  2. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  5. | 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
  6. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> explain select * from t2 where column_b=2;
  10. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  12. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  13. | 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
  14. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  15. 1 row in set (0.00 sec)
  16.  
  17. mysql> explain select * from t2 where column_c=3;
  18. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  19. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  20. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  21. | 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
  22. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
  23. 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++代码模板

    c++代码模板 &代码: #include <bits/stdc++.h> using namespace std; typedef long long ll; const int ...

  2. SG函数模板

    这篇虽然是转载的,但代码和原文还是有出入,我认为我的代码更好些. 转载自:http://www.cnblogs.com/frog112111/p/3199780.html 最新sg模板: //MAXN ...

  3. NeHe OpenGL教程 第三十九课:物理模拟

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  4. python(12)给文件读写上锁

    目的:当我们用脚本去爬取数据或者向文件中写数据的时候,有时候需要两个或者多个脚本同时向一个文件中读写 于是乎就会出现写乱的情况,于是乎我们就需要把正在写的文件先锁起来,只让当前的写,写完后再释放 代码 ...

  5. 在sql脚本中将查询结果集拼接成字符串

  6. linux常用命令 3

    示例定义的 mytest或者test 用户 mygroup 用户组 cat /etc/group 查看组 groupname:x:groupId:其他成员 组名:x(加密):组ID:组成员cat /e ...

  7. 使用SVN进行项目版本管理

    1.摘要 本文描述了利用SVN进行项目版本管理的方法,涉及项目版本号命名规则.SVN目录结构.第三方代码库的管理.版本创建.发布.修订.合并等行为的方法和原则. 2.版本号命名规则 版本号采用主版本号 ...

  8. mysqldump 数据库迁移并改换engine

    1. 导出数据库 mysqldump -h172.18.165.xxx -P3306 -uroot -pxxx --add-drop-database --default-character-set= ...

  9. .net 程序集自动生成版本号

    一. 版本号自动生成方法 只需把 AssemblyInfo.cs文件中的 [assembly:AssemblyVersion("1.0.0.0")]改成 [assembly:Ass ...

  10. WebService中实现上传下载文件

    不多说,直接看代码: /*上传文件的WebService*/ using System; using System.Collections; using System.Collections.Gene ...