数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建 查询 更新和删除数据 不同的存储引擎提供不同的存储机制 索引技巧 锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能 现在许多不同的数据库管理系统都支持多种不同的数据引擎 MySql的核心就是插件式存储引擎。

一.MySQL的存储引擎

在MySQL下面,我们输入命令:

1
SHOW ENGINES

就可以查看MySQL的存储引擎。

在MySQL中,不需要在整个服务器中使用同一种存储引擎,针对具体的要求,可以对每一个表使用不同的存储引擎 Support列的值表示某种引擎是否能使用:YES表示可以使用 NO表示不能使用 DEFAULT表示该引擎为当前默认的存储引擎 下面来看一下其中几种常用的引擎。

1.InnoDB

InnoDB是事务型数据库的默认引擎,只有在需要它不支持的特性时,才考虑用其它的存储引擎。

  • 主索引是聚簇索引,在索引中保存了数据从而避免直接读取磁盘,因此对查询性能有很大的提升;
  • 支持事务(ACID);
  • 支持行级锁和外键;
  • 实现了四个标准的隔离级别,默认级别是可重复读。在可重复读的隔离级别下,通过多版本并发控制(MVCC)+间隙锁(Next-Key Locking)防止幻影读;
  • 支持提交(COMMIT)、回滚(ROLLBACK)、崩溃恢复;
  • 支持真正的在线热备份;
  • 内部做了很多优化,包括从磁盘读取数据时采用的可预读性读,能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。

2.MyISAM

设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。

提供了大量的特性,包括压缩表、空间数据索引等。

  • 不支持事务和外键;
  • 不支持行级锁,但支持表级锁,读取时会对需要读到的所有表加共享锁(S锁),写入时则对表加排它锁(X锁)。但在表有读取操作的时候,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT);
  • 可以手动或自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的;
  • 不支持在线热备份;
  • 不支持崩溃后的安全恢复,MyISAM崩溃后发生损坏的概率比InnoDB高很多,而且恢复速度也很慢;
  • 支持BLOB和TEXT的前500个字符索引,支持全文索引
  • 支持延迟更新索引,极大地提升了写入性能;
  • 对于不会进行修改的表,支持 压缩表 ,极大地减少了磁盘空间的占用。

使用MyISAM引擎创建数据库,将产生3个文件,文件的名字以表名字开始,扩展名之处文件类型:frm文件存储表定义,数据文件的扩展名为.MYD(MYData) 索引文件的扩展名时.MYI(MYIndex)。

3.MEMORY

MEMORY存储引擎将表中的数据存储到内存中,为查询和引用其他表数据提供快速访问。

所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

4.存储引擎的选择

在实际工作中,选择一个合适的存储引擎是一个比较复杂的问题,每种存储引擎都有自己的优缺点,不能笼统地说谁比谁好,但建议选择使用InnoDB。

如果你的应用程序一定要使用事务,毫无疑问你要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。比如DELETE FROM mytable这样的删除语句。

如果你的应用程序对查询性能要求较高,就要使用MYISAM了。MYISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MYISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。

《MySQL高性能》上面有一句话这样写到:

不要轻易相信“MyISAM比InnoDB快”之类的经验之谈,这个结论往往不是绝对的。在很多我们已知场景中,InnoDB的速度都可以让MyISAM望尘莫及,尤其是用到了聚簇索引,或者需要访问的数据都可以放入内存的应用。

一般情况下我们选择 InnoDB 都是没有问题的,但是某事情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择MyISAM也是一个不错的选择。但是一般情况下,我们都是需要考虑到这些问题的。

注意:同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。

二.为什么InnoDB用B+树做索引

1.B+树和红黑树的比较

为什么MySQL用B+树作为其搜索引擎而不用红黑树呢?

如果不了解红黑树可以先看看红黑树的介绍红黑树

红黑树等平衡树也是可以用来实现索引的,但文件系统以及数据库系统普遍采用B+树作为索引结构,主要有以下两个原因:

  1. 更少的查找次数

    平衡树查找操作的时间复杂度和树高h相关,O(h)=O(logdN),其中d为每个节点的出度。

    红黑树的出度为2,而B+树的出度一般都比较大,至少是可以大于2的,所以红黑树的树高h很明显比B+树大的多,所以查找的次数也就更多。

  2. 利用磁盘预读原理

    AVL 树(平衡二叉树)和红黑树(二叉查找树)基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致效率低下的情况。为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写。磁盘I/O代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读写。根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B+树的一个节点可以有多个子女,从几十到上千,可以降低树的高度。

    为了减少I/O操作,磁盘往往不是严格按需读取,而是每次都会预读。在预读的过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,速度切回非常快。

    数据库系统的设计者巧妙利用了磁盘预读原理,将索引的一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

2.B+树和B树的比较

B+树是大多数MySQL存储引擎的索引类型,

B树是MongoDB的索引类型

区别

B+树:

  1. 数据只出现在叶子节点
  2. 所有叶子节点之间有链指针

B树:

  1. 树内每个节点都存储数据
  2. 叶子节点之间无指针相连

三.聚簇索引

聚集索引与非聚集索引的区别是:叶节点是否存放一整行记录

InnoDB 主键使用的是聚簇索引,MyISAM 不管是主键索引,还是二级索引使用的都是非聚簇索引。

下图形象说明了聚簇索引表(InnoDB)和非聚簇索引(MyISAM)的区别:

1.对于非聚簇索引表来说(右图),表数据和索引是分成两部分存储的,主键索引和二级索引存储上没有任何区别。使用的是B+树作为索引的存储结构,所有的节点都是索引,叶子节点存储的是索引+索引对应的记录的数据。

2.对于聚簇索引表来说(左图),表数据是和主键一起存储的,主键索引的叶结点存储行数据(包含了主键值),二级索引的叶结点存储行的主键值。使用的是B+树作为索引的存储结构,非叶子节点都是索引关键字,但非叶子节点中的关键字中不存储对应记录的具体内容或内容地址。叶子节点上的数据是主键与具体记录(数据内容)。

聚簇索引的优点

1.当你需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好。

2.当通过聚簇索引查找目标数据时理论上比非聚簇索引要快,因为非聚簇索引定位到对应主键时还要多一次目标记录寻址,即多一次I/O。

3.使用覆盖索引扫描的查询可以直接使用页节点中的主键值。

聚簇索引的缺点

1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。

2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。

3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

二级索引的叶节点存储的是主键值,而不是行指针(非聚簇索引存储的是指针或者说是地址),这是为了减少当出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空间。

4.采用聚簇索引插入新值比采用非聚簇索引插入新值的速度要慢很多,因为插入要保证主键不能重复,判断主键不能重复,采用的方式在不同的索引下面会有很大的性能差距,聚簇索引遍历所有的叶子节点,非聚簇索引也判断所有的叶子节点,但是聚簇索引的叶子节点除了带有主键还有记录值,记录的大小往往比主键要大的多。这样就会导致聚簇索引在判定新记录携带的主键是否重复时进行昂贵的I/O代价。

参考文章