索引是在存储引擎中实现的,而不是在服务器层中实现的。所以,每种存储引擎的索引都不一定完全相同,并不是所有的存储引擎都支持所有的索引类型。
b-tree 索引是 mysql 数据库中使用最为频繁的索引类型,除了 archive 存储引擎之外的其他所有的存储引擎都支持 b-tree 索引。不仅在mysql 中是如此,在其他的很多数据库管理系统中 b-tree 索引也同样是作为最主要的索引类型的,这主要是因为 b-tree索引的存储结构在数据库的数据检索中有着非常优异的表现。
一般来说,MySQL 中的 B-Tree 索引的物理文件大多是以 Balance Tree 的结构来存储的,也就是所有实际需要的数据都存放于 Tree 的Leaf Node,而且到任何一个 Leaf Node的最短路径的长度都是完全相同的,所以把它称之为 B-Tree 索引。不过,可能各种数据库(或 MySQL 的各种存储引擎)在存放自己的 B-Tree 索引的时候会对存储结构稍作改造。如 InnoDB 存储引擎的 B-Tree 索引使用的存储结构实际上是 B+Tree,在 B-Tree 数据结构的基础上做了很小的改造,在每一个 Leaf Node 上面除了存放索引键的相关信息之外,还存储了指向与该 Leaf Node 相邻的后一个 Leaf Node 的指针信息,这主要是为了加快检索多个相邻 Leaf Node 的效率。
在 InnoDB 存储引擎中,存在两种不同形式的索引,一种是 Cluster 形式的主键索引(Primary Key),另外一种则是和其他存储引擎(如MyISAM存储引擎)存放形式基本相同的普通 B-Tree 索引,这种索引在 InnoDB 存储引擎中被称为 Secondary Index。
两种索引在 Root Node 和Branch Nodes 方面完全一样。但它们会在Leaf Nodes方面出现差异。在 Primary Key 中,Leaf Nodes 存放的是表的实际数据,不仅仅包括主键字段的数据,还包括其他字段的数据,整个数据以主键值有序的排列。而 Secondary Index 则和其他普通的 B-Tree 索引没有太大的差异,只是在 Leaf Nodes除了存放索引键的相关信息外,还存放了 InnoDB 的主键值。
所以,在 InnoDB 中如果通过主键来访问数据效率是非常高的,而如果是通过 Secondary Index 来访问数据的话,InnoDB 首先通过 Secondary Index 的相关信息及相应的索引键检索到 Leaf Node,再通过Leaf Node 中存放的主键值和主键索引来获取相应的数据行。
MyISAM 存储引擎的主键索引和非主键索引差别很小,只不过主键索引的索引键是一个唯一且非空的键。而且 MyISAM 存储引擎的索引和 InnoDB 的 Secondary Index 的存储结构基本相同,主要的区别只是 MyISAM 存储引擎在 Leaf Nodes 上除了存放索引键信息之外,还存放能直接定位到 MyISAM 数据文件中相应数据行的信息(如Row Number),但并不会存放主键的键值信息。
举例说明
假设有如下一个表:
CREATE TABLE People (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum('m', 'f') not null,
key(last_name, first_name, dob)
);
其索引包含表中每一行的last_name、first_name和dob列。
可以利用B-Tree索引进行全关键字、关键字范围和关键字前缀查询,当然,如果想使用索引,你必须保证按索引的最左边前缀(leftmost prefix of the index)来进行查询:
(1)匹配全值(Match the full value):对索引中的所有列都指定具体的值。
(2)匹配最左前缀(Match a leftmost prefix):你可以利用索引查找last name为Allen的人,仅仅使用索引中的第1列。
(3)匹配列前缀(Match a column prefix):例如,你可以利用索引查找last name以J开始的人,这仅仅使用索引中的第1列。
(4)匹配值的范围查询(Match a range of values):可以利用索引查找last name在Allen和Barrymore之间的人,仅仅使用索引中第1列。
(5)匹配部分精确而其它部分进行范围匹配(Match one part exactly and match a range on another part):可以利用索引查找last name为Allen,而first name以字母K开始的人。
(6)仅对索引进行查询(Index-only queries):如果查询的列都位于索引中,则不需要读取元组的值。
由于B-树中的节点都是顺序存储的,所以可以利用索引进行查找(找某些值),也可以对查询结果进行ORDER BY。
当然,使用B-tree索引有以下一些限制:
(1) 查询必须从索引的最左边的列开始。关于这点已经提了很多遍了。例如你不能利用索引查找在某一天出生的人。
(2) 不能跳过某一索引列。例如,你不能利用索引查找last name为Smith且出生于某一天的人。
(3) 存储引擎不能使用索引中范围条件右边的列。例如,如果你的查询语句为WHERE last_name="Smith" AND first_name LIKE 'J%' AND dob='1976-12-23',则该查询只会使用索引中的前两列,因为LIKE是范围查询。