A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

MySQL的索引详解之索引基础1、概要
MySQL中,索引(index)也叫做“键(key)”,它是存储引擎用于快速找到记录的一种数据结构。
索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对性能的影响就愈发重要。
索引优化应该是对查询性能优化最有效的手段,创建一个真正最优的索引经常需要重写SQL查询语句。
2、索引的工作原理
要理解MySQL中索引的工作原理,最简单的方法就是去看一看一本书的索引部分:比如你想在一本书中寻找某个主题,一般会先看书的索引目录,找到对应的章节、对应的页码后就可以快速找到你想看的内容。
MySQL中,存储引擎用类似的方法使用索引,其先在索引中查找对应的值,然后根据匹配的索引记录找到对应的数据行,最后将数据结果集返回给客户端。
3、 索引的类型
MySQL中,通常我们所指的索引类型,有以下几种:
常规索引
常规索引,也叫普通索引(index或key),它可以常规地提高查询效率。一张数据表中可以有多个常规索引。常规索引是使用最普遍的索引类型,如果没有明确指明索引的类型,我们所说的索引都是指常规索引。
主键索引
主键索引(Primary Key),也简称主键。它可以提高查询效率,并提供唯一性约束。一张表中只能有一个主键。被标志为自动增长的字段一定是主键,但主键不一定是自动增长。一般把主键定义在无意义的字段上(如:编号),主键的数据类型最好是数值。
唯一索引
唯一索引(Unique Key),可以提高查询效率,并提供唯一性约束。一张表中可以有多个唯一索引。
全文索引
全文索引(Full Text),可以提高全文搜索的查询效率,一般使用Sphinx替代。但Sphinx不支持中文检索,Coreseek是支持中文的全文检索引擎,也称作具有中文分词功能的Sphinx。实际项目中,我们用到的是Coreseek。
外键索引
外键索引(Foreign Key),简称外键,它可以提高查询效率,外键会自动和对应的其他表的主键关联。外键的主要作用是保证记录的一致性和完整性。
注意:只有InnoDB存储引擎的表才支持外键。外键字段如果没有指定索引名称,会自动生成。如果要删除父表(如分类表)中的记录,必须先删除子表(带外键的表,如文章表)中的相应记录,否则会出错。 创建表的时候,可以给字段设置外键,如 foreign key(cate_id) references cms_cate(id),由于外键的效率并不是很好,因此并不推荐使用外键,但我们要使用外键的思想来保证数据的一致性和完整性。
4、 索引的方法
MySQL中,索引是在存储引擎层实现的,而不是在服务器层。MySQL支持的索引方法,也可以说成是索引的类型(这是广义层面上的),主要有以下几种:
B-Tree 索引
如果没有特别指明类型,那多半说的就是B-Tree 索引。不同的存储引擎以不同的方式使用B-Tree索引,性能也各不相同。例如:MyISAM使用前缀压缩技术使得索引更小,但InnoDB则按照原始的数据格式存储索引。再如MyISAM通过数据的物理位置引用被索引的行,而InnoDB则根据主键引用被索引的行。
B-Tree 对索引列是顺序存储的,因此很适合查找范围数据。它能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据。
如果一个索引中包括多个字段(列)的值,那它就是一个复合索引。复合索引对多个字段值进行排序的依据是创建索引时列的顺序。如下:
create table people (
    id int unsigned not null auto_increment primary key comment '主键id',
    last_name varchar(20) not null default '' comment '姓',
    first_name varchar(20) not null default '' comment '名',
    birthday date not null default '1970-01-01' comment '出生日期',
    gender tinyint unsigned not null default 3 comment '性别:1男,2女,3未知',
    key(last_name, first_name, birthday)
) engine=innodb default charset=utf8;
people表中也已经插入了如下一些数据:
id
last_name
first_name
birthday
gender
       1
Clinton
Bill
1970-01-01
       3
       2
Allen
Cuba
1960-01-01
       3
       3
Bush
George
1970-01-01
       3
       4
Smith
Kim
1970-01-01
       3
       5
Allen
Cally
1989-06-08
       3
       …
       …
我们创建了一个复合索引 key(last_name, first_name, birthday),对于表中的每一行数据,该索引中都包含了姓、名和出生日期这三列的值。索引也是根据这个顺序来排序存储的,如果某两个人的姓和名都一样,就会根据他们的出生日期来对索引排序存储。
B-Tree 索引适用于全键值、键值范围或键前缀查找,其中键前缀查找只适用于根据最左前缀查找。
复合索引对如下类型的查询有效:
全值匹配
全值匹配指的是和索引中的所有列进行匹配。例如:查找姓Allen、名Cuba、出生日期为1960-01-01的人。SQL语句为:select id,last_name,first_name,birthday from people where last_name=’Allen’ and first_name=’Cuba’ and birthday=’1960-01-01’;。
匹配最左前缀
比如只使用索引的第一列,查找所有姓为Allen的人。SQL语句为:select id,last_name,first_name,birthday from people where last_name=’Allen’;。
匹配列前缀
比如只匹配索引的第一列的值的开头部分,查找所有姓氏以A开头的人。SQL语句为:select id,last_name,first_name,birthday from people where last_name like ‘A%’;。
匹配范围值
比如范围匹配姓氏在Allen和Clinton之间的人。SQL语句为:select id,last_name,first_name,birthday from people where last_name BETWEEN ‘Allen’ And ‘Clinton’;。这里也只使用了索引的第一列。
精确匹配第一列并范围匹配后面的列
比如查找姓Allen,并且名字以字母C开头的人。即全匹配复合索引的第一列,范围匹配第二列。SQL语句为:select id,last_name,first_name,birthday from people where last_name = ‘Allen’ and first_name like’C%’;。
只访问索引的查询
B-Tree 通常可以支持“只访问索引的查询”,即查询只需要访问索引,而无需访问数据行。这和“覆盖索引”的优化相关,后面再讲。
下面介绍一些复合索引会失效的情况:
1)如果不是按照复合索引的最左列开始查找,则无法使用索引。例如:上面的例子中,索引无法用于查找查找名为Cuba的人,也无法查找某个特定出生日期的人,因为这两列都不是复合索引 key(last_name, first_name, birthday) 的最左数据列。类似地,也无法查找姓氏以某个字母结尾的人,即like范围查询的模糊匹配符%,如果放在第一位会使索引失效。
2)如果查找时跳过了索引中的列,则只有前面的索引列会用到,后面的索引列会失效。比如查找姓Allen且出生日期在某个特定日期的人。这里查找时,由于没有指定查找名(first_name),故MySQL只能使用该复合索引的第一列(即last_name)。
3)如果查询中有某个列的范围查询,则该列右边的所有列都无法使用索引优化查找。例如有查询条件为 where last_name=’Allen’ and first_name like ‘C%’ and birthday=’1992-10-25’,这个查询只能使用索引的前两列,因为这里的 like 是一个范围条件。假如,范围查询的列的值的数量有限,那么可以通过使用多个等于条件代替范围条件进行优化,来使右边的列也可以用到索引。
现在,我们知道了复合索引中列的顺序是多么的重要,这些限制都和索引列的顺序有关。在优化性能的时候,可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求,比如在一张表中,可能需要两个复合索引 key(last_name, first_name, birthday) 和 key(first_name, last_name, birthday) 。
B-Tree索引是最常用的索引类型,后面,如果没有特别说明,都是指的B-Tree索引。
哈希索引
哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有列的查询才有效。在MySQL中,只有Memory引擎显示支持哈希索引。
空间数据索引(R-Tree)
MyISAM引擎支持空间索引,可以用作地理数据存储。和B-Tree索引不同,该索引无须前缀查询。
全文索引
全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。全文索引和其他几种索引的匹配方式完全不一样,它更类似于搜索引擎做的事情,而不是简单的where条件匹配。可以在相同的列上,同时创建全文索引和B-Tree索引,全文索引适用于 Match Against 操作,而不是普通的where条件操作。
索引可以包含一个列(即字段)或多个列的值。如果索引包含多个列,一般会将其称作复合索引,此时,列的顺序就十分重要,因为MySQL只能高效的使用索引的最左前缀列。创建一个包含两个列的索引,和创建两个只包含一列的索引是大不相同的。
5、索引的优点
索引可以让MySQL快速地查找到我们所需要的数据,但这并不是索引的唯一作用。
最常见的B-Tree索引,按照顺序存储数据,所以,MySQL可以用来做Order By和Group By操作。因为数据是有序存储的,B-Tree也就会把相关的列值都存储在一起。最后,因为索引中也存储了实际的列值,所以某些查询只使用索引就能够获取到全部的数据,无需再回表查询。据此特性,总结出索引有如下三个优点:
索引大大减少了MySQL服务器需要扫描的数据量。索引可以帮助服务器避免排序和临时表。索引可以将随机I/O变为顺序I/O。
此外,有人用“三星系统”(three-star system)来评价一个索引是否适合某个查询语句。三星系统主要是指:如果索引能够将相关的记录放到一起就获得一星;如果索引中的数据顺序和查找中的排列顺序一致就获得二星;如果索引中的列包含了查询需要的全部列就获得三星。
索引并不总是最好的工具,也不是说索引越多越好。总的来说,只要当索引帮助存储引擎快速找到记录带来的好处大于其带来的额外工作时,索引才是有用的。
对于非常小的表,大部分情况下简单的全表扫描更高效,没有必要再建立索引。对于中到大型的表,索引带来的好处就非常明显了。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马