MySQL 的索引

索引简介

在 MySQL 中,索引(index)也叫做键(key),它是存储引擎用于快速找到记录的一种数据结构。

索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对性能的影响就愈发重要。

索引优化是对查询性能优化最有效的手段。

在 MySQL 中,通常我们所指的索引类型,有以下几种:

普通索引

普通索引(index 或 key)是指索引类型为 normal 的索引,或者创建索引时没有明确指定类型的索引。普通索引是使用最普遍的索引类型。

主键索引

主键索引(Primary Key),也简称主键。它可以提高查询效率,并提供唯一性约束。一张表中只能有一个主键。被标志为自动增长的字段一定是主键,但主键不一定是自动增长。一般把主键定义在无意义的字段上(如:编号),主键的数据类型最好是数值。

唯一索引

唯一索引(Unique Key),可以提高查询效率,并提供唯一性约束。一张表中可以有多个唯一索引。

全文索引

全文索引(Full Text),可以提高全文搜索的查询效率,一般使用 Sphinx 替代。但 Sphinx 不支持中文检索,Coreseek 是支持中文的全文检索引擎,也称作具有中文分词功能的 Sphinx。实际项目中,用的是 Coreseek。

外键索引

外键索引(Foreign Key),简称外键,它可以提高查询效率,外键会自动和对应的其他表的主键关联。外键的主要作用是保证记录的一致性和完整性。

注意:只有 InnoDB 存储引擎的表才支持外键。外键字段如果没有指定索引名称,会自动生成。如果要删除父表(如类目表)中的记录,必须先删除子表(带外键的表,如文章表)中的相应记录,否则会出错。 创建表的时候,可以给字段设置外键。由于外键的效率并不是很好,因此并不推荐使用外键,但我们要使用外键的思想来保证数据的一致性和完整性。

复合索引

在 MySQL 中,索引是在存储引擎层实现的,而不是在服务器层。如果没有特别指明类型,那多半说的就是 BTree 索引。不同的存储引擎以不同的方式使用 BTree 索引,性能也各不相同。例如:MyISAM 使用前缀压缩技术使得索引更小,但 InnoDB 则按照原始的数据格式存储索引。再如 MyISAM 通过数据的物理位置引用被索引的行,而 InnoDB 则根据主键聚集被索引的行。

BTree 对索引列是顺序存储的,因此很适合查找范围数据。它能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据。

复合索引也称组合索引、多列索引,是指包含多个字段的索引。

复合索引对多个字段值进行排序的依据是创建索引时列的顺序

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_first_bir(last_name, first_name, birthday)
) engine=innodb default charset=utf8;

插入一些测试数据:

INSERT people(id,last_name,first_name,birthday,gender) 
VALUES 
(0, 'Clinton', 'Bill', '1970-01-01', 3),
(0, 'Allen', 'Cuba', '1970-01-01', 3),
(0, 'Bush', 'George', '1970-01-01', 3),
(0, 'Smith', 'Kim', '1970-01-01', 3),
(0, 'Allen', 'Cally', '1989-06-08', 3);

我们创建了一个复合索引 key last_first_bir(last_name, first_name, birthday),对于表中的每一行数据,该索引中都包含了姓、名和出生日期这三列的值。索引也是根据这个顺序来排序存储的,如果某两个人的姓和名都一样,就会根据他们的出生日期来对索引排序存储。

Btree 索引适用于全键值、键值范围或键前缀查找,其中键前缀查找只适用于根据最左前缀查找

复合索引生效的几种方式

全值匹配

全值匹配指的是和索引中的所有列进行匹配。例如:查找姓 Allen、名 Cuba、出生日期为 1960-01-01 的人。

select id,last_name,first_name,birthday 
from people 
where last_name='Allen' and first_name='Cuba' and birthday='1970-01-01';

explain 分析的结果如下:

+----+-------------+--------+------------+------+----------------+----------------+---------+-------------------+------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys  | key            | key_len | ref               | rows | filtered | Extra       |
+----+-------------+--------+------------+------+----------------+----------------+---------+-------------------+------+----------+-------------+
|  1 | SIMPLE      | people | NULL       | ref  | last_first_bir | last_first_bir | 127     | const,const,const |    1 |   100.00 | Using index |
+----+-------------+--------+------------+------+----------------+----------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

说明: 改变 where 子句中的各个参数的顺序,对分析结果没有影响。

匹配复合索引的最左前缀

比如只使用索引的第一列,查找所有姓为 Allen 的人。

select id,last_name,first_name,birthday 
from people where last_name='Allen';

explain 分析结果如下:

mysql> explain select id,last_name,first_name,birthday
    -> from people where last_name='Allen';
+----+-------------+--------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys  | key            | key_len | ref   | rows | filtered | Extra       |
+----+-------------+--------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | people | NULL       | ref  | last_first_bir | last_first_bir | 62      | const |    2 |   100.00 | Using index |
+----+-------------+--------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

匹配列前缀

比如只匹配索引的第一列的值的开头部分,查找所有姓氏以 A 开头的人。

select id,last_name,first_name,birthday 
from people where last_name like 'A%';

explain 分析结果如下:

+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
| id | select_type | table  | partitions | type  | possible_keys  | key            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | people | NULL       | range | last_first_bir | last_first_bir | 62      | NULL |    2 |   100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

匹配范围值

比如范围匹配姓氏在 Allen 和 Clinton 之间的人。

select id,last_name,first_name,birthday 
from people where last_name BETWEEN 'Allen' And 'Clinton';

explain 分析结果如下:

+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
| id | select_type | table  | partitions | type  | possible_keys  | key            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | people | NULL       | range | last_first_bir | last_first_bir | 62      | NULL |    4 |   100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

精确匹配第一列并范围匹配后面的列

比如查找姓 Allenÿ

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值