[MySQL] 索引

目录

[1. 什么是索引](#1. 什么是索引)

[2. 索引使用的数据结构](#2. 索引使用的数据结构)

[2.1 B 树](#2.1 B 树)

[2.2 B+ 树](#2.2 B+ 树)

[3. Mysql中的页](#3. Mysql中的页)

[3.1 什么是页](#3.1 什么是页)

[3.2 页的结构](#3.2 页的结构)

[3.3 计算三层的B+树能够存储多少条记录](#3.3 计算三层的B+树能够存储多少条记录)

[3.4 优化表的大小](#3.4 优化表的大小)

[4. 索引的分类](#4. 索引的分类)

[4.1 主键索引](#4.1 主键索引)

[4.2 普通索引](#4.2 普通索引)

[4.3 唯一索引](#4.3 唯一索引)

[4.4 聚集索引](#4.4 聚集索引)

[4.5 非聚集索引](#4.5 非聚集索引)

[4.6 索引覆盖](#4.6 索引覆盖)

[4.7 一个表可以有多个索引](#4.7 一个表可以有多个索引)

[5. 使用索引](#5. 使用索引)

[5.1 自动创建索引](#5.1 自动创建索引)

[5.2 手动创建索引](#5.2 手动创建索引)

[5.2.1 创建主键索引](#5.2.1 创建主键索引)

[5.2.2 创建唯一索引](#5.2.2 创建唯一索引)

[5.2.3 创建普通索引](#5.2.3 创建普通索引)

[5.3 创建复合索引](#5.3 创建复合索引)

[5.4 查看索引](#5.4 查看索引)

[5.5 删除索引](#5.5 删除索引)

[5.5.1 删除主键索引](#5.5.1 删除主键索引)

[5.5.2 删除其他索引](#5.5.2 删除其他索引)

[5.6 创建索引注意事项](#5.6 创建索引注意事项)

[5.7 索引失效问题](#5.7 索引失效问题)


1. 什么是索引

索引是数据库中的数据结构,可以帮助我们快速的更新和查找数据。

索引需要消耗额外的内存空间,但是这些空间很小。

2. 索引使用的数据结构

2.1 B 树

B树是一个n叉搜索树,每个节点有n个子树,每个节点包含n-1个数据。有效的降低了树的高度。

因为mysql在查找的话,需要向硬盘申请数据,如果使用二叉搜索树的话,树的高度过高,每次都要申请数据,开销很大。

下面就是B树的结构:

2.2 B+ 树

mysql在B树的基础上进行了改进,得到一种新的数据结构B+树。

B+树的特点:

  • B+树的每一个节点都有N个节点,每个节点都有N个子节点,也就是每个节点的最后一个值是以这个节点为头结点的树的最大值。
  • B+树的父节点的值会作为子节点中最大的值出现。
  • 叶子节点会使用双向链表的形式串起来。
  • 叶子节点可以包含所有的数据的索引列,我们就可以在叶子节点找到对应的数据,因此非叶子节点只用存储索引列,叶子节点存储数据行。

下面就是一个B+树:

B+树相对于其他数据结构作为索引的优势:

  1. N叉搜索树,高度比较低,读写硬盘次数比较少。
  2. 所有的数据都存储在叶子节点中,最后的查询操作也是在叶子节点上进行的,所有在访问硬盘的次数是固定的。
  3. 叶子节点作为链表,适合范围查询。
  4. 非叶子节点只需要存储索引列,内存比较小,适合在内存中缓存,减少读取硬盘的次数。

3. Mysql中的页

3.1 什么是页

Mysql中的页指的是B+树上的每个节点,一个节点对应一页,一页的大小默认是16KB,MySQL在与硬盘进行读写操作时都是以页为单位的,并且每次MySQL读取时都至少读取一页,在硬盘中每个页内部的存储空间都是连续的,我们就可以读取一页,每页包含多条数据,下次用的数据在内存中就直接使用,不再的话就再读取,有效的减少了读取硬盘的次数。

这里利用到了局部性原理的思想:

时间局部性: 程序读取了某个数据,程序下一次大概率会读取到这个数据附近的某些数据。

空间局部性:程序读取到某个数据,未来某个时间大概率还会用到这个数据。

3.2 页的结构

数据库中的表是以.ibd文件存储在硬盘上的,每个文件都是二进制的数据,以页为单位进行组织的。

在我们使用索引查询表时候,如果这个表有主键,就以主键列创建索引,如果没有主键,就会生成一个隐藏列来创建索引。

每张页都有页头和页尾,包含索引列和数据行的页称为数据页,只包含索引列的称为索引页。

下面是数据页的大概结构:

页头大小为38字节,页尾大小为8字节,其余空间全是存储数据行的。

3.3 计算三层的B+树能够存储多少条记录

索引页的每条数据都是由索引列和页的编号组成。

假设索引列的大小为8字节,页的编号为6字节,那么一个索引数据就是14字节。

假设忽略页头和页尾,存储的都是索引行,可以存储 16 * 1024 / 14 大概等于 1170条索引行。

第一层一个节点,第二层1070个节点,第三层1070 * 1070个节点。

叶子节点保存数据行,假设叶子节点的每个数据行的大小为1KB,那么一页可以存储16条数据行。

一共能存储 1070 * 1070 * 16 = 21902400 条数据。

3.4 优化表的大小

我们如何将表的大小进行优化:

可以使用冷热分离将数据分成两个表,一个是热点数据表,一个是冷数据表。将经常使用的数据分到一个表里面,很少使用的数据分到另一个表里面。

我们还可以分库分表:通过表中的字段进行哈希运算,进行划分表。

4. 索引的分类

4.1 主键索引

表中的主键就是一个索引,如果表中没有唯一且不重复的列的话,就会由MySQL创建一个索引列。

4.2 普通索引

通过sql语句创建索引,可能包含多个列。

4.3 唯一索引

被unique修饰的列,就是唯一索引,该列元素不能重复。

4.4 聚集索引

InnoDB是MySQL中的数据存储模块,负责数据存储在硬盘上的。

当表中没有主键时候,InnoDB就会找到最先出现的被unique和not null修饰的列作为聚集索引。

如果上面都没有,InnoDB就会自己生成大小为6字节的行号ROW_ID列,此列递增,该列作为索引列。

4.5 非聚集索引

聚集索引以外的索引称为非聚集索引或者二级索引。

二级索引里面对应的行都包括该行的主键列,找到主键列后,再根据主键列找到对应的数据行。

4.6 索引覆盖

当select语句使用了普通索引,并且查询的列刚好是普通索引的部分列或者全部列,可以直接返回查询结果,不用进行回文操作,这就是索引覆盖。

4.7 一个表可以有多个索引

我们定义一个主键索引id,再定义一个name索引,这时候会有两个B+树,主键B+树叶子节点会存储数据行,name索引的B+树会存储id,我们利用name创建的索引去查数据时候,会先在name的B+树上查到对应id,然后再去另一棵树上去查找对应的数据行。这种查询两次的方式叫做回文。

这种回文的方法也比遍历查询的速度快。

5. 使用索引

5.1 自动创建索引

当我们为表添加主键约束,唯一约束,外键约束,会将对应列创建为索引。

如果上面都没有,mysql的数据存储模块(InnoDB)就会自动创建一个索引列ROW_ID。

5.2 手动创建索引

5.2.1 创建主键索引

sql 复制代码
#直接添加索引约束
create table student(
	id primary key auto_increment,
	name varchar(20)
);
#单独创建某列为主键
create table student(
	id auto_increment,
	name varchar(20),
	primary key(id)
);
#将某一列创建为主键索引
create table student(
	id int,
	name varchar(20)
);
alter table student add primary key(id);

5.2.2 创建唯一索引

sql 复制代码
#直接添加唯一约束
create table student(
	id primary key auto_increment,
	name varchar(20) unique
);
#单独创建某列为唯一索引
create table student(
	id primary key auto_increment,
	name varchar(20),
	unique(name)
);
#将某一列创建为唯一索引
create table student(
	id primary key auto_increment,
	name varchar(20)
);
alter table student add unique(name);

5.2.3 创建普通索引

sql 复制代码
#创建表时指定索引列
create table student(
	id primary key auto_increment,
	name varchar(20) unique,
	sno varchar(20),
	index(sno)
);
#修改表中的列为普通索引
create table student(
	id primary key auto_increment,
	name varchar(20),
	sno varchar(20)
);
alter table student add index(sno);
#单独创建索引并自己命名
create table student(
	id primary key auto_increment,
	name varchar(20),
	sno varchar(20)
);
create index index_sno on student(sno);

5.3 创建复合索引

创建符合索引的过程和创建普通索引的过程基本相同,只是复合索引包含多个列:

sql 复制代码
#创建表时候创建复合索引
create table student(
	id int primary key auto_increment,
	name varchar(20),
	sno varchar(20),
	class_id int,
	index(sno,class_id)
);
#修改表中的某些列为复合索引
create table student(
	id int primary key auto_increment,
	name varchar(20),
	sno varchar(20),
	class_id int,
);
alter table student add index(sno,class_id);
#单独创建索引并命名
create table student(
	id int primary key auto_increment,
	name varchar(20),
	sno varchar(20),
	class_id int,
);
create index index_name on student(sno,class_id);

5.4 查看索引

sql 复制代码
#方法一:
show keys from 表名;
#方法二:
show index from 表名;
#方法三:
desc 表名;

5.5 删除索引

5.5.1 删除主键索引

sql 复制代码
alter table 表名 drop primary key;
#如果有自增约束,先去除约束
alter table 表名 modify id int;
alter table 表名 drop primary key;

5.5.2 删除其他索引

sql 复制代码
#语法
alter table 表名 drop index 索引名;

5.6 创建索引注意事项

对于一些很大的表来说,创建索引是很危险的,因为要进行大量的硬盘的IO操作。

我们应该把索引创建在查询频率高的列上。

一般最初设计表的时候,就规划好了索引。

假设一台mysql的服务器正在运行,如何给这台服务器添加索引?

我们可以找到一台未工作的服务器,将添加好索引的数据搭建在这台服务器上,然后将应用程序接到新的服务器上。

5.7 索引失效问题

我们创建索引,如果没有使用,那么依旧是采用遍历表的方式查询数据,那么此时的索引就属于失效,没有使用。

单个列索引:

  1. 在查询时候,查询条件中没有索引列。
  2. 在查询过程中,查询条件使用了索引列,但是索引列比较单一,比如性别:男/女,依然要遍历整个表。
  3. 查询时候,查询条件对查询列进行了表达式计算或者隐式类型转换,比如:id + 10 > 50。
  4. 查询条件包含or,并且一边是包含索引列,一边不包含索引列,比如:id > 20 or class_id < 10。
  5. 查询条件字符串查询包含like,并且是"%孙"这种形式的。
  6. 查询条件是 i= 或者 not 之类的。
  7. 多个表联合查询,但是表之间的字符集不同。

复合索引:

假设有a b c d e f 六个列,我们设置a b c三个列为复合索引,我们会先根据a索引来查询,相同的话,再根据b索引,还相同,再根据c索引来查。如果我们根据a来查后直接根据c来查就会失效。

我们可以使用explain关键字来查看SQL语句的 是否使用索引,以及使用的那种索引。

相关推荐
lang201509284 小时前
Spring Boot SQL数据库全攻略
数据库·spring boot·sql
EndingCoder5 小时前
MongoDB基础与Mongoose ODM
服务器·javascript·数据库·mongodb·中间件·node.js
赋能大师兄5 小时前
SQLITE数据库完成数据增删改查
数据库·sqlite
一个天蝎座 白勺 程序猿6 小时前
深度解析:通过ADO.NET驱动Kdbndp高效连接与操作Kingbase数据库
数据库·.net·wpf·kingbase·金仓数据库
AI科技星6 小时前
垂直原理:宇宙的沉默法则与万物运动的终极源头
android·服务器·数据结构·数据库·人工智能
Warren986 小时前
复习MySQL
数据库·windows·tcp/ip·mysql·ubuntu·ssh·ansible
黑金IT6 小时前
3D虚拟人模型转换的完整指南
服务器·数据库·3d
凌~风6 小时前
数据库原理实验报告:在ider里搭建mysql数据库
数据库·mysql·实验报告
keke_俩个科6 小时前
ShardingSphere分库分表基础配置与使用说明
java·数据库·分布式·spring