MYSQL索引与存储引擎

目录

  • 前言
    • 数据结构
      • 二叉树结构
      • 红黑树结构
      • B-Tree结构
        • B树
        • B+树
      • HASH结构
    • 存储引擎介绍
      • MylSAM (轻量级)-非聚集
      • InnoDB-聚集
    • 索引
      • 普通索引(INDEX)
      • 唯一索引
      • 主键索引(PRIMARY KEY)
      • 联合索引
      • 全文索引(FULLTEXT)
    • 总结

学习数据结构网站(可以加快对索引的理解):Data Structure Visualizationsl
MYSQL索引与存储引擎_第1张图片

前言

Mysql是一个程序员必须要学会的一种语言,很多人新手小白虽然会基础使用Mysql,但是不明白其索引设计的原理。

要先明白什么是索引,索引是高效帮助MySql获取数据的数据结构。

  • 索引存储在文件系统中,并且文件存储形式与存储引擎有关。
  • 索引(index)是在存储引擎(storage engine)层面实现的,而不是在server层面。
  • 索引是在存储引擎中实现的,不同引擎会使用不同索引类型。
  • 索引的文件结构
    • hash
    • 二叉树
    • 红黑树(二叉平衡树)
    • B树(B-tree)
    • B+树(B+tree)

最近我的项目就经常需要使用索引进行调优,因此了解了相应知识,此次我就将自己理解的整理起来。

数据结构

二叉树结构

MYSQL索引与存储引擎_第2张图片
如图所示,二叉树的结构是,以根节点为基准,比较小的放右边,大的放左边。
因此当搜索时,根据数据一个一个搜索,效率相对比较慢

红黑树结构

MYSQL索引与存储引擎_第3张图片
如图所示,同样的数据,二叉树和红黑树对比的数据结构却不一样。
黑色为根节点,红色为叶节点,红黑树的特点就是能够平衡数据。其原理与二叉树一样,但是多了一个平衡数据的算法,因此红黑树又称二叉平衡树。

当我们看到这里肯定会有疑问,既然红黑树这么好用,为什么 索引最终底层结构是B-Tree,为什么呢?

原因很简单,其实我们在公司真实使用的数据绝对不止展示的数据可言的,基本都上千万,上亿的数据量。
如果用红黑树,最后其实也和用二叉树没什么区别。
其实涉及到一个词, 深度,我们以二叉树举例,我们看到的数据量可以换成2 ^ n,而n就是深度,也就是所谓的高度;
当我们的数据量上千万甚至上亿,那么他的深度是多少?如果刚好我们要查询的数据恰好处在极端位置,那查询效率也不高!而B树就刚好解决这个问题!

B-Tree结构

B树

MYSQL索引与存储引擎_第4张图片
B-Tree是优化红黑树改的高度,而进行横向扩展,致使结构深度比较小,查询效率也比较快。

B+树

MYSQL索引与存储引擎_第5张图片

HASH结构

若设置索引时除了BTREE还有一个HASH这个索引。
底层选择Hash表存储时,会将索引的每个字段做HASH运算,得到一个结果值,将这个结果值以及对应的数据磁盘地址指针存储到HASH映射表里。只要将查询条件做Hash运算,得到结果直接去映射表里查找。

  • hash索引查询极为快速,为什么实际却用的少?
    • 如果只是精准查询时可以使用Hash索引,因为Hash索引对范围查找支持极差!select * from user where user_id = xxx / select * from user where user_id > xxx(Hash索引支持差)
      在这里插入图片描述

存储引擎介绍

Mysql虽然提供很多数据存储引擎,但我们接触最多还是两种存储引擎MylSAMInnoDB,此次也只介绍这两种存储引擎。

MylSAM (轻量级)-非聚集

MylSAM是早期的版本(MYSQL 5.5.5之前)默认的存储引擎,特点是:

  1. 不支持事务
  2. 表级锁定形式,数据在更新时锁定整个表
  3. 数据库在读写过程中相互阻塞
  4. 可通过key_buffer_size来设置缓存索引,提高访问性能,减少磁盘IO的压力,但缓存只会缓存索引文件,不会缓存数据
  5. 不支持外键约束,只支持全文索引
  6. 数据单独写入或读取,速度过程较快且占用资源相对少

MylSAM对应的文件有三个:.frm、.MYI和*.MYD(MYI存的是索引值,MYD存的是数据值)

总的来说,MylSAM比较适合用在查询为主的业务

MylSAM一般索引是采用B树和B+树

叶子节点data域存放的是数据的物理地址,索引结构和真正的数据结构其实是分开存储的(索引和数据是分开的)。

InnoDB-聚集

目前新版本已经将InnoDB作为默认的存储引擎,相比与MylSAM,InnoDB有更完善的事务支持,也支持外键和行级锁。特点有:

  1. 支持事务(四个特性ACID)(口诀:一致支持原子持久隔离),可以把事务当成执行sql
    ① 原子性(Atomicity):事务是一个完整的操作,只要事务中任何一个元素失败,则整个事务失败回滚。
    ② 一致性(Consistency):事务完成前后,数据必须处在一致状态(意思:不会出现有些数据还在更新和删除状态)
    ③ 隔离性 (Isolation):所有并发的事务都是彼此隔离的,相互独立互不干扰。
    ④ 持久性(Durability) :不管系统是否发生故障,事务处理的结果都是永久的;一旦事务提交后,事务执行后的结果将会永久保留在数据库中。
  2. 行级锁定,但是全表扫描仍然会是表级锁定读写阻塞与事务隔离级别相关
  3. 具有非常高效的缓存特性:既能缓存索引文件,也能缓存数据(导致更大占用鞥多存储空间)
  4. 支持外键约束,5.5版本后才支持全文索引
  5. 对硬件资源要求比较高

InnoDB对应的文件有两个:*.frm和 *.ibd(ibd里索引和数据都存在一起)。

索引实现

  • 便数据文件本身就是按B+Tree组织的一个索引结构文件
  • 聚集索引-叶节点包含了完整的数据纪律
  • 为什么InnoDB必须有主键,并且推荐使用整型的自增主键?
    答案: MySql设计时就是按照B+Tree组织的,要求必须要一个主键,若没有主键数据是无法组织的。
    • 如果我们在建表时没有设置主键,InnoDB会自动寻找所有字段中能成为唯一主键的值;若没有,则会自动添加一列隐藏的RowId作为唯一主键。(设计就是如此!)
    • 至于使用uuid字符串作为主键,而不是整形的自增主键时,uuid的查询效率会比自增的主键性能慢。因为InnoDB使用的B+Tree结构,整形数字比较是否比字符串比较快。
    • 除了性能快以外,由于字符串占用空间也比较大,推荐使用的整形相对占用空间比较小。
    • 至于为什么用自增?我们看图片的结构,是不是有个箭头指针,底层的索引都是递增的趋势,方便维护数据,这也时B+Tree的特性。
      MYSQL索引与存储引擎_第6张图片

至于还有几种存储引擎,比较少用也比较少了解,在这里就简单介绍,MEMORY/HEAP存储引擎,该引擎支持HASH和BTREE索引。

索引

我们知道Mysql的索引主要分为两种:

  • 聚簇索引(或称→ 辅助索引
  • 非聚簇索引(或称→二级索引

两者的区别:聚簇索引是索引文件和数据文件放在一起为一个文件,因此查询效率比较高;非聚簇索引是索引文件和数据文件分开连个文件。
因此InnoDb是聚簇,MylSAM是非聚簇。
MYSQL索引与存储引擎_第7张图片
这里引用‘王下邀月熊’的图片
而索引的实际应用,也是我们常用的几种:

  • 普通索引
    • 普通索引也就是所谓的单列索引,将数据表的一列作为索引字段。
  • 唯一索引(允许为空)
    • 唯一索引的字段必须时唯一的,但允许又空值。
  • 主键索引(不允许为空)
    • 主键索引是一种特殊唯一索引,因为主键索引必须是主键,一个表只有一个主键,也不允许为空。一般在建表时就会自动创建主键索引
  • 外键索引
  • 组合(联合)索引
    • 组合索引也就是所谓的联合索引,也就是多个字段创建索引,著有在查询条件where中使用我们创建索引时的第一个字段,联合索引才会被使用。这类索引遵循最左前缀集合。
  • 全文索引

以上都是我们比较熟知的一些Mysql索引。

当然也有一些我们所不太熟知的索引,比如空间索引 SPATIAL,原本只有在MylSAM引擎上才能使用,在MySQL5.7版本后InnoDB也开始支持。空间索引是对空间数据类型(坐标,地理位置等)的字段建立的索引,MySQL中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。==创建空间索引的列,必须将其声明为NOT NULL。==在这里就不多介绍了!

普通索引(INDEX)

(1)直接创建索引

CREATE INDEX index_name ON table(column(length)) 

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

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

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

CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (title(length))
)

(4)删除索引

DROP INDEX index_name ON table

唯一索引

(1)直接创建索引

CREATE UNIQUE INDEX indexName ON table(column(length))

(2)修改表结构

ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))

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

CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    UNIQUE indexName (title(length))
);

主键索引(PRIMARY KEY)

主键索引是一种特殊唯一索引,因为主键索引必须是主键,一个表只有一个主键,也不允许为空。
建表时就会自动创建主键索引

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

联合索引

联合索引就是将表里的几个字段建立一个组合索引

ALTER TABLE `table` ADD INDEX index_x_y (xxxx,yyyy); 

而这样的组合索引,其实就相当于建立两个索引:

—xxxx,yyyy
—xxxx

至于上面提到的"最左前缀",简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:

 –使用到上面的索引
 SELECT * FROM table WHREE xxxx='xxxx' AND yyyy='yyyy';
 SELECT * FROM table WHREE xxxx='xxxx';

 –不使用上面的索引
 SELECT * FROM table WHREE yyyy='yyyy';

全文索引(FULLTEXT)

(1)创建表时创建全文索引

create table index_text(
    id int(11) NOT NULL AUTO_INCREMENT,
    content text NOT NULL,
    tag varchar(255),
    PRIMARY KEY (id),
    indextext KEY index_content (content,tag)  // 创建联合全文索引列
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

(2)在已存在的表上创建全文索引

create indextext index index_content on index_text(content,tag);

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

alter table index_textadd indextext index content_tag_fulltext(content,tag);

使用全文索引
和常用的模糊匹配使用 like + % 不同,全文索引有自己的语法格式,使用 match 和 against 关键字,比如:

select * from fulltext_test where match(content,tag) against('xxx xxx');

注意: match() 函数中指定的列必须和全文索引中指定的列完全相同,否则就会报错,无法使用全文索引,这是因为全文索引不会记录关键字来自哪一列。如果想要对某一列使用全文索引,请单独为该列创建全文索引。

总结

MySQL学习必须要从底层的存储引擎和索引开始学起,之后才会更好的了解如何sql调优。不管工作还是面视,都是需要学习的!

你可能感兴趣的:(MySql,mysql,索引,数据库)