高性能MySQL05-索引原理

一、简介

索引类似于书籍的目录,要想找到一本书的某个特定主题,需要先查找书的目录,定位对应的页码。

存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的值,然后根据匹配的索引找到对应的数据行。一般来说,在WHERE和JOIN中出现的列需要建立索引,但也不完全如此,因为MySQL只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE才会使用索引。

索引有很多种类型,都是实现在存储引擎层的。Mysql主要支持如下几种索引:

1)普通索引
2)唯一索引
3)主键索引
4)组合索引
5)全文索引

二、语法

CREATE TABLE table_name[col_name data type]
[unique|fulltext][index|key][index_name](col_name[length])[asc|desc]

1)unique|fulltext为可选参数,分别表示唯一索引、全文索引
2)index和key为同义词,两者作用相同,用来指定创建索引
3)col_name为需要创建索引的字段列,该列必须从数据表中该定义的多个列中选择
4)index_name指定索引的名称,为可选参数,如果不指定,默认col_name为索引值
5)length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度
6)asc或desc指定升序或降序的索引值存储

例 :

# 1)添加INDEX(普通索引) 
    mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column` ) 
# 2)添加UNIQUE(唯一索引) 
    mysql>ALTER TABLE `table_name` ADD UNIQUE ( `column`) 
# 3)添加PRIMARY KEY(主键索引) 
    mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 
# 4)添加组合索引 
    mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`)
# 5)添加FULLTEXT(全文索引) 
    mysql>ALTER TABLE `table_name` ADD FULLTEXT ( `column`) 

相关操作:

# 查看表结构
    desc table_name;
# 查看生成表的SQL
    show create table table_name;
# 查看索引
    show index from  table_name;
    show keys from table_name;
# 查看执行时间
    set profiling = 1;
    SQL...
    show profiles;
# 查看索引的使用情况
    show status like '%Handler_read%' ;

三、索引的机制

传统的查询方法,是按照表的顺序遍历的,不论查询几条数据,mysql需要将表的数据从头到尾遍历一遍。在我们添加完索引之后,mysql一般通过BTREE算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历(折半查找大幅查询效率),找到相应的键从而获取数据。

1、索引对性能的影响:
1)创建索引是为产生索引文件的,占用磁盘空间
2)大大减少服务器需要扫描的数据量
3)帮助服务器避免排序和临时表
4)将随机I/O变顺序I/O
5)虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行insert、update和delete。因为更新表时,不仅要保存数据,还要保存一下索引文件(因为dml操作同样也会对索引文件进行修改)。

2、在哪些column上使用索引:
1)较频繁的作为查询条件字段应该创建索引
2)唯一性太差的字段不适合创建索引,尽管频繁作为查询条件,例如gender性别字段
3)更新非常频繁的字段不适合作为索引
4)不会出现在where子句中的字段不该创建索引

3、索引的创建原则:
1)最适合索引的列是出现在WHERE子句中的列,或连接子句中的列而不是出现在SELECT关键字后面的列。
2)索引列的基数越大,索引的效果越好。
3)对字符串进行索引,应该制定一个前缀长度,可以节省大量的索引空间
4)根据情况创建复合索引,复合索引可以提高查询效率
5)避免创建过多索引,索引会额外占用磁盘空间,降低写操作效率
6)主键尽可能选择比较短的数据类型,可以有效减少索引的磁盘占用,提高查询效率。

4、索引的使用场景

1)对于非常小的表,大部分情况下全表扫描效率更高
2)中到大型表,索引非常有效
3)特大型的表,建立和使用索引的代价将随之增长,可以使用分区技术来解决

四、索引类型

1、普通索引
是最基本的索引,它没有任何限制。它有以下几种创建方式:
1)直接创建索引

CREATE INDEX index_name ON `table` (`column`(length));

2)修改表结构的方式添加索引

ALTER TABLE `table_name` ADD INDEX index_name (`column`(length))

3)创建表的时候同时创建索引

CREATE TABLE `c` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
    `content` text NULL ,
    PRIMARY KEY (`id`),
    INDEX title (`title`(5))
);

4)删除索引

DROP INDEX index_name ON `table`;

2、唯一索引
与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
1)创建唯一索引

CREATE UNIQUE INDEX index_name ON `table` (`column`(length));

2)修改表结构

ALTER TABLE `table_name` ADD UNIQUE index_name (`column`(length));

3)创建表的时候直接指定

CREATE TABLE `d` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
    `content` text NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    UNIQUE title (`title`(5))
);

3、主键索引
是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。主键可以与外键构成参照完整性约束,防止数据不一致。

一般是在建表的时候同时创建主键索引:

CREATE TABLE `e` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
    PRIMARY KEY (`id`)
);

4、组合索引
将多个列组合在一起创建索引。
只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合。

ALTER TABLE `table` ADD INDEX name_city_age (`name`,`city`,`age`); 

5、全文索引
MySQL自带的全文索引只能用于MyISAM,对文本的内容进行分词,进行搜索。

主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。fulltext索引配合match against操作使用,而不是一般的where语句加like。它可以在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多。

1)创建表的时候添加全文索引

CREATE TABLE `article` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
    `content` text NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    FULLTEXT (content)
);

2)修改表结构添加全文索引

ALTER TABLE `article` ADD FULLTEXT index_content (`content`);

3)直接创建索引

CREATE FULLTEXT INDEX index_content ON `article` (`content`);

6、外键
用于建立和加强两个表数据之间的链接的一列或多列。外键约束主要用来维护两个表之间数据的一致性。简言之,表的外键就是另一表的主键,外键将两表联系起来。一般情况下,要删除一张表中的主键必须首先要确保其它表中的没有相同外键。比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。

外键的使用条件:
① 两个表必须是InnoDB表,MyISAM表暂时不支持外键
② 外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引,但如果在较早的版本则需要显式建立;
③ 外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如int和tinyint可以,而int和char则不可以;

五、注意事项

1、复合索引遵循前缀原则

# 如复合索引:KEY(a,b,c)
# 如下查询方式索引有效:
WHERE a = 1 and b = 2 and c = 3
WHERE a = 1 and b = 2
WHERE a = 1
# 如下方式索引无效:
WHERE b = 2 and c = 3
WHERE a = 1 and c = 3

2、以通配符%和_开头作查询时,MySQL不会使用索引。
3、column is null 可以使用索引
4、如果MySQL估计使用索引比全表扫描更慢,会放弃使用索引
5、如果or前的条件中的列有索引,后面的没有,索引都不会被用到
6、列类型是字符串,查询时一定要给值加引号,否则索引失效
7、不要在索引列上进行运算,这将导致索引失效,如:

SELECT * FROM table_name WHERE YEAR(column_name)<2017;

六、经典实例

1、简单描述MySQL中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响?

2、创建MySQl复合索引应该注意哪些事项?

[答案参考本文]

参考

1、《高性能MySQL》 [美]Baron Scbwartz, Peter Zaitsev, Vadim Tkacbenko 著
2、 蹲厕所的熊MySQL索引原理以及慢查询优化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章