MySQL之存储引擎及索引

810 阅读9分钟

存储引擎

存储引擎是MySQL的组件,用于处理不同表类型的SQL操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以获得特定的功能。

使用哪一种引擎可以灵活选择,一个数据库中多个表可以使用不同引擎以满足各种性能和实际需求,使用合适的存储引擎,将会提高整个数据库的性能 。

MySQL服务器使用可插拔的存储引擎体系结构,可以从运行中的 MySQL 服务器加载或卸载存储引擎 。

存储引擎对比

常见的存储引擎基本就InnoDB、MyISAM、Memory。

文件存储结构对比

MyISAM

当我们使用MyISAM存储引擎时,就会在本地磁盘上创建三个文件,文件名就是表名

  • .frm文件:存储表相关的元数据信息,包括表结构的定义信息
  • .MYD文件:存储表中数据的信息
  • .MYI文件:存储表索引的相关信息

InnoDB

作为MySQL默认的存储引擎,会生成两个文件

  • .frm文件:存储表相关的元数据信息,包括表结构的定义信息
  • .ibd文件:存储表中数据及索引的相关信息

Memory

MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。

每个基于MEMORY存储引擎的表实际对应一个磁盘文件。该文件的文件名与表名相同,类型为 frm 类型。该文件中只存储表的结构。而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要了,可以释放内存,甚至删除不需要的表。

MEMORY默认使用哈希索引。速度比使用B型树索引快。当然如果你想用B型树索引,可以在创建索引时指定。

注意,MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。如果重启或者关机,所有数据都会消失。因此,基于MEMORY的表的生命周期很短,一般是一次性的。

对比项MyISAMInnoDB
主外键不支持支持
事务不支持支持
行表锁表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作
缓存只缓存索引,不缓存真实数据不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响
表空间
关注点性能事务
默认安装
  • InnoDB 是聚簇索引,MyISAM 是非聚簇索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

  • InnoDB 不保存表的具体行数,执行select count(*) from table 时需要全表扫描。而 MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快。

  • MyISAM表会把自增主键的最大ID记录到数据文件中,重启MySQL自增主键的最大ID也不会丢失;而InnoDB 表只是把自增主键的最大ID记录到内存中,所以重启数据库会导致最大ID丢失。

  • 在 MyISAM 存储引擎中,把表的总行数存储在磁盘上。

索引

  • 索引(Index)是帮助MySQL高效获取数据的数据结构,所以说索引的本质是:数据结构

  • 索引的目的在于提高查询效率。

  • 可以简单的理解为“排好序的快速查找数据结构”,数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

  • 索引本身也很大,不可能全部存储在内存中,一般以索引文件的形式存储在磁盘上

  • 平常说的索引,没有特别指明的话,就是B+树结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引。此外还有哈希索引等。

MySQL索引结构

首先要明白索引(index)是在存储引擎(storage engine)层面实现的,而不是server层面。不是所有的存储引擎都支持所有的索引类型。即使多个存储引擎支持某一索引类型,它们的实现和行为也可能有所差别。

B+Tree索引

MyISAM 和 InnoDB 存储引擎,都使用 B+Tree的数据结构,它相对于 B-Tree结构,所有的数据都存放在叶子节点上,且把叶子节点通过指针连接到一起,形成了一条数据链表,以加快相邻数据的检索效率。

至于为什么使用B+Tree作为索引结构而不是B-Tree,简单来说就是为了减少IO次数,提高查询效率。当系统从磁盘读取数据到内存的时候是以磁盘块(block)为单位的,位于同一个磁盘块中的数据会被一次性读取出来,而B+Tree相对于B-Tree的区别就是所有的数据都存放在叶子节点上,非叶子节点只存储索引信息,这样在加载的时候就能够一次性尽可能多的加载索引信息来查询数据。

MyISAM主键索引与辅助索引的结构

MyISAM引擎的索引文件和数据文件是分离的。MyISAM引擎索引结构的叶子节点的数据域,存放的并不是实际的数据记录,而是数据记录的地址。索引文件与数据文件分离,这样的索引称为"非聚簇索引"。MyISAM的主索引与辅助索引区别并不大,只是主键索引不能有重复的关键字。

在MyISAM中,索引(含叶子节点)存放在单独的.myi文件中,叶子节点存放的是数据的物理地址偏移量(通过偏移量访问就是随机访问,速度很快)。

InnoDB主键索引与辅助索引的结构

InnoDB引擎索引结构的叶子节点的数据域,存放的就是实际的数据记录(对于主索引,此处会存放表中所有的数据记录;对于辅助索引此处会引用主键,检索的时候通过主键到主键索引中找到对应数据行),或者说,InnoDB的数据文件本身就是主键索引文件,这样的索引被称为"“聚簇索引”,一个表只能有一个聚簇索引。InnoDB 表推荐使用整型自增主键。

为什么推荐使用整型自增主键?

  • 在B+树中进行查找时需要跟经过的节点值比较大小,整型数据能够快速比较;
  • 自增的整型索引在磁盘中会连续存储,在读取一页数据时也是连续,且适合执行where id > 5 && id < 20的条件查询语句。
  • 在插入或删除数据时,整型自增主键会在叶子结点的末尾建立新的叶子节点,不会破坏左侧子树的结构。

Hash索引

  • 主要就是通过Hash算法,将数据库字段数据转换成定长的Hash值,与这条数据的行指针一并存入Hash表的对应位置;如果发生Hash碰撞,则在对应Hash键下以链表形式存储。

    检索算法:在检索查询时,就再次对待查关键字再次执行相同的Hash算法,得到Hash值,到对应Hash表对应位置取出数据即可,如果发生Hash碰撞,则需要在取值时进行筛选。目前使用Hash索引的数据库并不多,主要有Memory等。

哪些情况需要创建索引

  1. 主键自动建立唯一索引
  2. 频繁作为查询条件的字段
  3. 单键/组合索引的选择问题,高并发下倾向创建组合索引
  4. 查询中排序的字段,排序字段通过索引访问大幅提高排序速度
  5. 查询中统计或分组字段

哪些情况不要创建索引

  1. 表记录太少
  2. 经常增删改的表
  3. 数据重复且分布均匀的表字段,只应该为最经常查询和最经常排序的数据列建立索引(如果某个数据类包含太多的重复数据,建立索引没有太大意义)
  4. 频繁更新的字段不适合创建索引(会加重IO负担)
  5. where条件里用不到的字段不创建索引

MySQL高效索引

覆盖索引(Covering Index),或者叫索引覆盖, 也就是平时所说的不需要回表操作

  • 就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖

  • 索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据,当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含(覆盖)满足查询结果的数据就叫做覆盖索引。

  • 判断标准

    使用explain,可以通过输出的extra列来判断,对于一个索引覆盖查询,显示为using index,MySQL查询优化器在执行查询前会决定是否有索引覆盖查询