目录
一、索引的介绍
- 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
- 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。
- 我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
二、索引的优劣
优势
- 可以提高数据检索的效率,降低数据库的IO成本,类似于书的目录。
- 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
- 被索引的列会自动进行排序,包括【单列索引】和【组合索引】,只是组合索引的排序要复杂一些。
- 如果按照索引列的顺序进行排序,对应order by语句来说,效率就会提高很多。
劣势
索引会占据磁盘空间
索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。
三、索引的结构
MySQL绝大部分情况下使用B+树
1、Hash结构
Hash结构的特点
- Hash 索引仅能满足(=) (<>)和IN 查询。因为Hash索引指向的数据是无序的,所以进行范围查询时,时间复杂度会退化为O(n);而树型的“有序”特性,依然能够保持o(log2N)的高效率。
- Hash 索引还有一个缺陷,数据的存储是没有顺序的,在ORDER BY的情况下,使用 Hash 索引还需要对数据重新排序。
- 对于联合索引的情况,Hash 值是将联合索引键合并后一起来计算的,无法对单独的一个键或者几个索引键进行查询。
- 对于等值查询来说,通常 Hash 索引的效率更高,不过也存在一种情况,就是 索引列的重复值如果很多,效率就会降低。这是因为遇到 Hash 冲突时,需要遍历桶中的行指针来进行比较,找到查询的关键字,非常耗时。所以,Hash 索引通常不会用到重复值多的列上,比如列为性别、年龄的情况等。
Hash索引的适用场景
- Hash 索引存在着很多限制,相比之下在数据库中 B+ 树索引的使用面会更广,不过也有一些场景采用 Hash 索效率更高,比如在键值型 (Key-Value) 数据库中,Redis 存储的核心就是 Hash 表。
- MySQL中的 Memory 存储引擎支持 Hash 存储,如果我们需要用到查询的临时表时,就可以选择 Memory存储引擎,把某个字段设置为 Hash 索引,比如字符串类型的字段,进行 Hash 计算之后长度可以缩短到几个字节。当字段的重复度低,而且经常需要进行 等值查询 的时候,采用 Hash 索引是个不错的选择。
- 另外,InnoDB 本身不支持 Hash 索引,但是提供自适应 Hash 索引 (Adaptive Hash ndex)。什么情况下才会使用自适应 Hash 索引呢?如果某个数据经常被访问,当满足一定条件的时候,就会将这个数据页的地址存放到Hash 表中,这样下次查询的时候,就可以直接找到这个页面的所在位置。这样让 B+ 树也具备了 Hash 索引的优点。
# 查看自适应hash索引是否启用 SHOW variables LIKE '%adaptive_hash_index%';
2、B树
3、B+树
B+树的特点
- 有k 个孩子的节点就有k 个关键字。也就是孩子数量 = 关键字数,而 B 树中,孩子数量= 关键字数 +1。
- 非叶子节点的关键字也会同时存在在子节点中,并且是在子节点中所有关键字的最大(或最小)。
- 非叶子节点仅用于索引,不保存数据记录,跟记录有关的信息都放在叶子节点中。而B 树中,非叶子节点既保存索引,也保存数据记录。
- B+树所有关键字都在叶子节点出现,叶子节点构成一个有序链表,而且叶子节点本身按照关键字的大小从小到大顺序链接。所以很擅长范围的查找。
四、MySQL索引的实现
1、MyIsam索引
主键索引:
- MyISAM的数据文件和索引文件是分开存储的。MyISAM使用B+树构建索引树时,叶子节点中存储的键值为索引列的值,数据为索引所在行的磁盘地址。
- 表user的索引存储在索引文件
user.MYI
中,数据文件存储在数据文件user.MYD
中。辅助索引:
- 在 MyISAM 中,辅助索引和主键索引的结构是一样的,没有任何区别,叶子节点的数据存储的都是行记录的磁盘地址。只是主键索引的键值是唯一的,而辅助索引的键值可以重复。
- 查询数据时,由于辅助索引的键值不唯一,可能存在多个拥有相同的记录,所以即使是等值查询,也需要按照范围查询的方式在辅助索引树中检索数据。
2、InnoDB索引
主键索引(聚簇索引):
每个InnoDB表都有一个聚簇索引 ,聚簇索引使用B+树构建,叶子节点存储的数据是整行记录。一般情况下,聚簇索引等同于主键索引,当一个表没有创建主键索引时,InnoDB会自动创建一个ROWID字段来构建聚簇索引。InnoDB创建索引的具体规则如下:
- 在表上定义主键PRIMARY KEY,InnoDB将主键索引用作聚簇索引。
- 如果表没有定义主键,InnoDB会选择第一个不为NULL的唯一索引列用作聚簇索引。
- 如果以上两个都没有,InnoDB 会使用一个6 字节长整型的隐式字段 ROWID字段构建聚簇索引。该ROWID字段会在插入新行时自动递增。
辅助索引:
- 除聚簇索引之外的所有索引都称为辅助索引。在中InnoDB,辅助索引中的叶子节点存储的数据是该行的主键值都。 在检索时,InnoDB使用此主键值在聚簇索引中搜索行记录。
3、MyIsam和InnocentDB对比
MyISAM的索引方式都是“非聚族”的,与innoDB包含1个聚族索引是不同的。小结两种引擎中索引的区别:
- 在innoDB存储引擎中,我们只需要根据主键值对聚簇索引进行一次查找就能找到对应的记录,而在 MyISAM 中却需要进行一次回表操作,意味着MyISAM中建立的索引相当于全部都是二级索引。
- lnnoDB的数据文件本身就是索引文件,而MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。
- lnnoDB的非聚族索引data域存储相应记录主键的值,而MySAM索引记录的是地址。换句话说,InnoDB的所有非聚簇索引都引用主键作为data域。
- MyISAM的回表操作是十分快速 的,因为是拿着地址偏移量直接到文件中取数据的,反观InnoDB是通过获取主键之后再去聚簇索引里找记录,虽然说也不慢,但还是比不上直接用地址去访问。
- lnnoDB要求表必须有主键( MyISAM可以没有 )。如果没有显式指定,则MySQL系统会自动选择一个可以非空目唯一标识数据记录的列作为主键。如果不存在这种列,则MVSOL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整型。
五、索引声明和使用
1、索引的分类
- 按功能逻辑分类:唯一索引、全文索引、主键索引、普通索引;
- 按物理实现分类:聚簇索引、非聚簇索引;
- 按作用字段个数:单列索引、联合索引。
2、索引的语法操作
- 索引的创建
# 1 隐式的创建索引(主键约束、唯一性约束、外键约束的字段上) # 2 显示的创建 CREATE TABLE 表名 (id int, lname varchar(20) [UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [索引名字] (索引字段列 [索引长度]) [ASC | DESC]); # 3 在已创建的表中添加索引 ALTER TABLE 表名 ADD INDEX [索引名字] (索引字段列 [索引长度]); CREATE INDEX [索引名字] ON 表名(索引字段列 [索引长度]);
- 索引的查看
# 方式一 SHOW CREATE TABLE 表名; # 方式二 SHOW INDEX FROM 表名;
- 索引的删除
# 方式一 ALTER TABLE 表名 DROP INDEX 索引名字; # 方式二 DROP INDEX 索引名字 ON 表名;
- MySQL8.0新特性
- 降序索引,支持DESC降序排列
- 隐藏索引
# 创建表时创建隐藏索引 CREATE TABLE (id INT, INDEX 索引名称(索引字段) invisible); # 创建表后添加隐藏索引 ALTER TABLE 表名 ADD INDEX 索引名称(索引字段) invisible; CREATE INDEX 索引名称 ON 表名(索引字段) invisible; # 修该索引的可见性 ALTER TABLE 表名 ALERT INDERX 索引名 visible/invisible;
六、索引的设置原则
1、哪些情况适合加索引
- 具有唯一特性的字段
- 频繁作为WHERE查询条件的字段
- 经常GROUP BY和ORDER BY的列
- 频繁UPDATE、DELETE、的WHERE条件列
- DISTINCT字段需要创建索引
- 多表JOIN连接操作时
- 连接表的数量金陵不要超过三张。
- 要对WHERE条件创建索引,可以更好的过滤。
- 对连接的字段创建索引,且连接的字段必须类型一致,否则索引会失效。
- 使用列的类型小的创建索引
- 使用字符串的前缀创建索引
- 在Varchar字段创建索引时,必须指明索引长度
- 使用前缀索引时,无法支持使用索引排序
- 区分度高(散列度)高的适合作为索引
- 创建联合索引时,使用越频繁的列越要放在左侧
- 在多个字段都要创建索引的情况下,联合索引优于单值索引
- 单表中不要超过6个索引
- 索引占用磁盘空间,索引越多,需要的磁盘空间越大。
- 索引会影响INSERT、DELETE、UPDATE等语句的性能。
- 当可选多个索引时,优化器在选择索引时会耗费时间。
2、哪些情况不适合加索引
- 在WHERE中使用不到的字段,不需要设置索引
- 数据量小的表不适合加索引
- 有大量重复数据的不要创建索引
- 经常更新数据的表或字段不要创建过多的索引
- 不建议用无序的值作为索引(例如身份证号)
- 删除不使用或很少使用的索引
- 不要定义冗余或重复的索引,例如联合索引和单值索引