1.MYSQL索引
1.1.索引的概述
MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构。
在数据之外,数据库系统还维护着特定查找算法的数据结构,这些数据结构以某种方式应用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引,如下图所示:
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻)。为了加快Col2的查找,可以维护一个右边所示的二叉树,每一个节点分别包含索引键值和一个指向对应对应数据物理地址的指针,这样就可以运用二叉查找快速获取到对应数据。一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的方式存储在磁盘上,索引是数据库中用来提高性能的常用工具。
1.2.索引优势劣势
优势
1、类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本
2、通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗
劣势
1、实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用磁盘空间的
2、虽然索引大大提高了查询效率,同时却降低了更新表的速度,如对表进行insert、update、delete。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
1.3.索引结构
索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种引擎的索引都不一定完全相同,也不是所有的存储引擎都支持索引索引类型的。MySQL目前提供了已下4种索引:
- BTREE索引:最创建的索引类型,大部分索引都支持B树索引。
- HASH索引:只有Memory引擎支持,使用场景简单
- R-tree索引(空间索引):空间索引是MylSAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
- Full-text(全文索引):全文索引也是MylSAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。
索引 InnoDB引擎 MylSAM引擎 Memory引擎 BTREE索引 支持 支持 支持 HASH 不支持 不支持 支持 R-tree 不支持 支持 不支持 Full-text 5.6版本之后支持 支持 不支持 我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用B+tree树索引,统称为索引。
1.3.1BTREE结构
概念:
BTree【B树】又叫多路平衡搜索树,一颗m叉的B树特性如下:
- 树中每个节点最多包含m个孩子
- 除根节点与叶子结点外,每个节点至少有【ceil(m/2) ==>> (m除以2向上取整)】个孩子
- 若根节点不是叶子节点,则至少有两个孩子
- 所有的叶子节点都在同一层
- 每个非叶子节点由n个key与n+1个指针组成,其中【ceil(m/2)-1】<= n <= m-1
演示案例:
以5叉B树为例,key的数量:公式推导【ceil(m/2)-1】<= n <= m-1。所以2 <= 3 <= 4。当n>4时,中间的节点分裂到父节点,两边节点分裂。
插入C N G A H E K Q M F W L T Z D P R X Y S N P Q R数据为例,演变过程如下:
24个英文字母排序顺序:【A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 】
1、插入前4个字母C N G A。字母的插入顺序是从小到大,上面的元素表示Key下面的单元格表示指针(根据公式:每个非叶子节点由n个key与n+1个指针组成,其中【ceil(m/2)-1】<= n <= m-1)最终结果如下图:
2、插入H,H是在G的后面但是此时 n>4 中间元素G字母应该向上分裂到新的节点
3、插入 E K Q,应为在两边插入元素时n的值没有大于4 所以不需要分裂
4、插入M,中间元素M字母向上分裂到父节点G
5、插入F、W、L、T不需要分裂
6、插入Z,中间元素T向上分裂到父节点中
7、插入D,中间元素D向上分裂到父节点中。然后插入P、R、X、Y不需要分裂
8、最后插入S,N P Q R节点n>5,中间节点Q向上分裂,但分裂后父节点DGMT的n>5,中间节点M向上分裂
到此,该BTREE树就已经构建完成了,BTREE树和二叉树相比,查询数据的效率更高,因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索的速度快。
1.3.2.B+TREE结构
B+TREE为BTREE的变种,B+TREE与BTREE的区别为:
1、n叉B+TREE最多含有n个key,而BTREE最多含有n-1个key
2、B+TREE的叶子节点保存所有的Key信息,依Key大小顺序排列
3、所有的非叶子节点都可以看作是key的索引部分
B+TREE结构如下图:
由于B+TREE只有叶子节点保存Key信息,查询任何Key都要从root走到叶子。所以B+TREE的查询效率更加稳定。
1.3.3.MySQL中的B+TREE
MySQL索引数据结构对经典的BTREE进行了优化。在原BTREE的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的BTREE,提高区间访问性能
MySQL中的B+TREE索引结构示意图如下:
1.4.索引的分类
1、单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
2、唯一索引:索引列的值必须唯一,但运行有空值
3、复合索引:即一个索引包含多个列
1.5.索引语法
索引在创建表的时候,可以同时创建,也可以随时增加新的索引。
准备环境:
CREATE DATABASE `mysql_senior` DEFAULT CHARACTER SET utf8;
use mysql_senior;
# 城市表
CREATE TABLE `city`
(
`city_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '城市ID',
`city_name` varchar(50) NOT NULL COMMENT '城市名称',
`country_id` int(11) NOT NULL COMMENT '国家ID'
);
INSERT into `city`
values (1, '江苏', 1),
(2, '上海', 1),
(3, '北京', 1),
(4, '广州', 1);
# 国家表
CREATE TABLE `country`
(
`country_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '国家ID',
`country_name` varchar(50) NOT NULL COMMENT '国家名称'
);
insert into `country`
values (1, '中国');
1.5.1.创建索引
语法:
create [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type] on table_name(index_col_name,...); # UNIQUE 唯一索引 # FULLTEXT 全文索引 # SPATIAL 空间索引 # index_col_name:column_name[(length)][ASC|DESC]
示例:为city表中的city_name字段创建索引
# 为city_name字段创建索引 create index index_city_name on city(city_name);
查询索引:
# 查看索引 # show index from table_name; show index from city;
1.5.2.删除索引
语法:
drop index index_name on table_name # index_name 索引名称 # table_name 表名
1.5.3.ALTER命令
# 通过ALTER关键字来添加索引
# ps:column_list >> 字段列表
# 该语句添加一个主键,这意味着索引值必须是唯一的,并且不能为null
alter table table_name add primary key(column_list);
# 这条语句创建索引必须是唯一的(除了NULL外,NULL可能会出现多次)
alter table table_name add unique index_name(column_list);
# 添加普通索引,索引值可以出现多次
alter table table_name add index index_name(column_list);
# 该语句指定了索引为FULLTEXT,用于全文索引
alter table table_name add fulltext index_name(column_list);
1.6.索引设计原则
索引的设置可以遵循一下已有的原则,创建索引的时候尽量的考虑复合这些原则,便于提升索引的使用效率,更高效的使用索引。
- 对查询频次比较高,且数据量比较大的表建立索引
- 索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合
- 索引可以有效的提升查询效率,但是索引的数量不是多多易善,索引越多,维护索引的代价自然就水涨船高。对应插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引起相当高的维护代价,降低DML操作的效率;增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。
- 使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MYSQL访问索引的I/O效率
- 利用最左前缀,N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率
# 创建复合索引 create index idx_nmae_email_status on table_name(name,email,status); /* 就相当于: 对name创建索引 对name,email创建了索引 对name,email,status创建了索引 */