「MySQL高级篇」MySQL逻辑架构,存储引擎

1,784 阅读17分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

大家好,我是melo,一名大二后台练习生,最近在提前感受MySQL面试题的毒打。

专栏回顾

引言

前边几篇文章,我们讲到了索引的原理&&设计原则,知道了索引如何使用。以及学会用explain来分析SQL,优化SQL 这篇呢,我们来放宽一下视野,总览一下MySQL的逻辑架构和存储引擎,之后,我们再挑其中的重要点,在下一篇文章中详细分析。

👉本篇速览

InnoDB,一个很耳熟的名词,这玩意到底是个什么东东,ta还有哪几个兄弟姐妹

这篇将从如下几点,带你攻破逻辑架构和存储引擎: ​

  • 逻辑架构层次
  • 不同的存储引擎
  • InnoDB和MyISAM的区别
  • 其他存储引擎
  • 存储引擎的选择原则

逻辑架构

可以类比我们的MVC架构

  1. 首先是连接层,对外展示,让外界可以通过一定技术连接到我们mysql,如jdbc,.NET,PHP等

  2. 之后就是一整个Server服务层,里边有很多个模块

    1. Connection Pool : 连接池组件
    2. Management Services & Utilities : 管理服务和工具组件
    3. SQL interface,来分辨出是DML还是DDL,view,trigger等
    4. Parser 解析器,解析客户端发起的请求,去掉注释?像一个沙漏一样
    5. Optimizer 优化器
    6. Caches & Buffers 缓存
  3. 引擎层

    1. Pluggable Storage Engines 可插拔存储引擎,可以随时更换
  4. 存储层

    1. File System : 文件系统(本质上操作的都是文件)

1) 连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。 ​

2) 服务层 第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如 过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定表的查询的顺序,是否利用索引等, 最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。 ​

3) 引擎层 存储引擎层, 存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。 ​

4)存储层 数据存储层, 主要是将数据存储在文件系统之上,并完成与存储引擎的交互。 ​

和其他数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎上,插件式的存储引擎架构,将查询处理和其他的系统任务以及数据的存储提取分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

🎮热插拔

  • 此处的插拔式可以理解为热插拔喔,就是可以在不停掉系统的情况下,随时更换引擎,而不影响原本的系统。

机械键盘玩家表示老在行了,热插拔键盘yyds

对比一下,这是传统的电焊式(非热插拔): image.png

这是热插拔: image.png

图源:www.zhihu.com/question/40…

存储引擎

概述

和大多数的数据库不同,MySQL中有一个存储引擎的概念,针对不同的存储需求可以选择最优的存储引擎。 ​

存储引擎就是存储数据,建立索引,更新查询数据等等技术的实现方式 。存储引擎是基于表的,而不是基于库的。所以存储引擎也可被称为表类型。 ​

Oracle,SqlServer等数据库只有一种存储引擎。MySQL提供了插件式的存储引擎架构。所以MySQL存在多种存储引擎,可以根据需要使用相应引擎,或者编写存储引擎。 ​

MySQL5.0支持的存储引擎包含 : InnoDB 、MyISAM 、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED等,其中InnoDB和BDB提供事务安全表,其他存储引擎是非事务安全表。

🍠重点

  1. 存储引擎是基于的,而不是基于库!!!!
  2. 热插拔:我们可以在不重启MySQL的情况下,随时更换引擎,而不影响原本的系统。每个表也可以选择不同的存储引擎,虽然往往不建议这么做。

查看支持的引擎

show engines;

​查询当前数据库支持的存储引擎 image.png

  • Engine:存储引擎名称。
  • Support:是否支持该引擎以及该引擎是否为默认存储引擎,YES表示支持,NO表示不支持,DEFAULT表示为默认存储引擎。
  • Comment:存储引擎的简单介绍。
  • Transactions:表示该引擎是否支持事务。
  • XA:说明该存储引擎是否支持分布式事务
  • Savepoints:说明该存储引擎是否支持部分事务回滚

创建新表时如果不指定存储引擎,那么系统就会使用默认的存储引擎,MySQL5.5之前的默认存储引擎是MyISAM,5.5之后就改为了InnoDB,这俩有什么区别,为什么MyISAM变为了InnoDB,下文我们会谈及到这一点,也是面试时经常会问到的点

相关命令

-- 查看支持的存储引擎
SHOW ENGINES

-- 查看默认存储引擎
SHOW VARIABLES LIKE 'storage_engine'

--查看具体某一个表所使用的存储引擎,
show create table tablename

--准确查看某个数据库中的某一表所使用的存储引擎
show table status like 'tablename'
show table status from database where name="tablename"

设置存储引擎

-- 建表时指定存储引擎。默认的就是INNODB,不需要设置
CREATE TABLE t1 (i INT) ENGINE = INNODB;
CREATE TABLE t2 (i INT) ENGINE = MEMORY;

-- 修改存储引擎
ALTER TABLE t ENGINE = InnoDB;

-- 修改默认存储引擎,或者在配置文件my.cnf中修改默认引擎
SET default_storage_engine=NDBCLUSTER;

查看默认存储引擎

show variables like '%storage_engine%'

image.png

各种存储引擎特性

最常使用的两种存储引擎: InnoDB、MyISAM ;

特点INNODBMYISAMMEMORYMERGENDB
存储限制64TB没有
事务安全支持
锁机制行锁(适合高并发)表锁表锁表锁行锁
B树索引支持支持支持支持支持
哈希索引支持
全文索引支持(5.6版本之后)支持
集群索引支持
数据索引支持支持支持
索引缓存支持支持支持支持支持
数据可压缩支持
空间使用N/A
内存使用中等
批量插入速度
支持外键支持

InnoDB

InnoDB存储引擎是Mysql的默认存储引擎。InnoDB存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全。但是对比MyISAM的存储引擎,InnoDB写的处理效率差一些,并且会占用更多的磁盘空间以保留数据和索引。 ​

InnoDB存储引擎不同于其他存储引擎的特点,有如下几个 :

MVCC

InnoDB采用MVCC来支持高并发,并且实现了四个标准的隔离级别。其默认级别是 REPEATABLE READ(可重复读),并且通过间隙锁(next-key locking)策略防止幻读的出现。 间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。

这四个隔离级别,间隙锁等,我们在之后的锁和事务篇章,再来详细谈谈。

事务控制

create table goods_innodb(
	id int NOT NULL AUTO_INCREMENT,
	name varchar(20) NOT NULL,
    primary key(id)
)ENGINE=innodb DEFAULT CHARSET=utf8;

start transaction;

insert into goods_innodb(id,name)values(null,'Meta20');

commit;

🧂外键约束

MySQL支持外键的存储引擎只有InnoDB , 在创建外键的时候, 要求父表必须有对应的索引 , 子表在创建外键的时候, 也会自动的创建对应的索引。

这就是为什么我们没有创建索引的时候,只能选主键作为外键,因为主键会默认创建索引

在创建索引时, 可以指定在删除、更新父表时,对子表进行的相应操作,包括 RESTRICT、CASCADE、SET NULL 和 NO ACTION。 ​

  • RESTRICT(限制)和 NO ACTION相同, 是指 -> 删除父表时,如果子表有关联记录的情况时, 父表没法成功删除

如果删除的是子表的话,是没有约束的。

  • CASCADE表示父表在更新或者删除时,更新或者删除子表对应的记录;

相当于两者同步,共生死

  • SET NULL 则表示父表在更新或者删除的时候,子表的对应字段被SET NULL 。
  • 针对上面创建的两个表, 子表的外键指定是ON DELETE RESTRICT , 那么在主表删除记录的时候, 如果子表有对应记录, 则不允许删除,
    • ON UPDATE CASCADE 方式的,主表在更新记录的时候, 如果子表有对应记录, 则子表对应更新 。

小demo

下面两张表中 , country_innodb是父表 , country_id为主键索引,city_innodb表是子表,country_id字段为外键,对应于country_innodb表的主键country_id 。 ​

create table country_innodb(
	country_id int NOT NULL AUTO_INCREMENT,
    country_name varchar(100) NOT NULL,
    primary key(country_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;


create table city_innodb(
	city_id int NOT NULL AUTO_INCREMENT,
    city_name varchar(50) NOT NULL,
    country_id int NOT NULL,
    primary key(city_id),
    key idx_fk_country_id(country_id),
    CONSTRAINT `fk_city_country` FOREIGN KEY(country_id) REFERENCES country_innodb(country_id) ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ON DELETE RESTRICT:删除主表,如果有关联记录,不删除
-- ON UPDATE CASCADE:更新主表,如果子表有关联记录,更新子表记录

insert into country_innodb values(null,'China'),(null,'America'),(null,'Japan');
insert into city_innodb values(null,'Xian',1),(null,'NewYork',2),(null,'BeiJing',1);

删除country_id为1 的country数据:

 delete from country_innodb where country_id = 1;

image.png

查看外键

show create table city_innodb ;

image.png

文件存储方式

InnoDB 存储表和索引有以下两种方式 :
①. 使用共享表空间存储, 这种方式创建的表的表结构保存在.frm文件中, 数据和索引保存在 innodb_data_home_dir 和 innodb_data_file_path定义的表空间中,可以是多个文件。

②. 使用多表空间存储, 这种方式创建的表的表结构仍然存在 .frm 文件中,但是每个表的数据和索引单独保存在 .ibd 中。 image.png

锁机制

  • 是行锁而不是表锁

具体有关于锁方面的知识,我们后续锁与事务篇再详细探讨!!

MyISAM

  • 不支持事务,自然访问速度会比较快,比较适合大量的读操作select插入操作insert
  • 不支持外键。

文件存储方式

每个MyISAM在磁盘上存储成3个文件,其文件名都和表名相同,但拓展名分别是 :

  • .frm (存储表定义);
  • .MYD(MYData , 存储数据);
  • .MYI(MYIndex , 存储索引);

🍿InnoDB和MyISAM区别

  1. 外键和事务,以及锁机制(上文已提及到)
  2. InnoDB 是聚簇索引,MyISAM 是非聚簇索引

也叫主键索引和辅助索引

  • 聚簇索引的文件存放在主键索引的叶子节点上,而非聚簇索引需要两次查询,先查询到主键,然后再通过主键查询到数据。(在索引篇中的索引分类有更具体的解释,感兴趣的小伙伴可以先看看)。

  • MyISAM 是非聚簇索引,数据文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的。

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

当然,这里也不是绝对的,看下边的分析:

MyISAM 快的前提是:select count(*) 语句没有where条件,无需筛选,才能直接通过读出变量得到具体行数,如果需要筛选的话,自然没办法直接通过读取变量,就得到具体行数了。

🌭自增主键相关

这个可能会出现在面试题喔!!

8.0版本

  1. MyISAM:当我们数据库主键已经自增到16时,此时删除14,15,16这三条记录,MySQL重启后的下一次插入,会从17开始,因为MyISAM表会把自增主键的最大ID记录到数据文件中,重启MySQL自增主键的最大ID也不会丢失
  2. 而InnoDB 则不会,下一次插入是从14开始。因为InnoDB 表只是把自增主键的最大ID记录到内存中,所以重启MySQL或对表进行OPTION操作,都会导致最大ID丢失。

5.7版本

  • 5.7版本时,重启后最大ID都会丢失的。

MEMORY(了解)

Memory存储引擎将表的数据存放在内存中。每个MEMORY表实际对应一个磁盘文件,格式是.frm ,该文件中只存储表的结构,而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。 ​

MEMORY 类型的表访问非常地快,因为他的数据是存放在内存中的,并且默认使用HASH索引 , 但是服务一旦关闭,表中的数据就会丢失。

MERGE(了解,但是感觉还不错的样子)

MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,MERGE表本身并没有存储数据,对MERGE类型的表可以进行查询、更新、删除操作,这些操作实际上是对内部的MyISAM表进行的。

对于MERGE类型表的插入操作,是通过INSERT_METHOD子句定义插入的表,可以有3个不同的值,使用FIRST 或 LAST 值使得插入操作被相应地作用在第一或者最后一个表上,不定义这个子句或者定义为NO,表示不能对这个MERGE表执行插入操作。 ​

可以对MERGE表进行DROP操作,但是这个操作只是删除MERGE表的定义,对内部的表是没有任何影响的。 image.png 1)创建3个测试表 order_1990, order_1991, order_all , 其中order_all是前两个表的MERGE表 :

create table order_1990(
	order_id int ,
	order_money double(10,2),
	order_address varchar(50),
	primary key (order_id)
)engine = myisam default charset=utf8;


create table order_1991(
	order_id int ,
	order_money double(10,2),
	order_address varchar(50),
	primary key (order_id)
)engine = myisam default charset=utf8;


create table order_all(
	order_id int ,
	order_money double(10,2),
	order_address varchar(50),
	primary key (order_id)
)engine = merge union = (order_1990,order_1991) INSERT_METHOD=LAST default charset=utf8;

2)分别向两张表中插入记录

insert into order_1990 values(1,100.0,'北京');
insert into order_1990 values(2,100.0,'上海');

insert into order_1991 values(10,200.0,'北京');
insert into order_1991 values(11,200.0,'上海');

若是往order_all中插入一条记录 ,由于在MERGE表定义时,INSERT_METHOD 选择的是LAST,那么插入的数据会向最后一张表中插入。

insert into order_all values(100,10000.0,'西安');

image.png

🎆引擎选择原则

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合(但一般不到万不得已,不要混用多种存储引擎,否则可能带来一系列复杂的问题)。 以下是几种常用的存储引擎的使用环境: ​

  • InnoDB : 是Mysql的默认存储引擎,用于事务处理应用程序,支持外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询以外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。InnoDB存储引擎除了有效的降低由于删除和更新导致的锁定, 还可以确保事务的完整提交和回滚,对于类似于计费系统或者财务系统等对数据准确性要求比较高的系统,InnoDB是最合适的选择。

  • MyISAM : 如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。

  • MEMORY:将所有数据保存在RAM中,在需要快速定位记录和其他类似数据环境下,可以提供几块的访问。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,其次是要确保表的数据可以恢复,数据库异常终止后表中的数据是可以恢复的。MEMORY表通常用于更新不太频繁的小表,用以快速得到访问结果。

  • MERGE:用于将一系列等同的MyISAM表以逻辑方式组合在一起,并作为一个对象引用他们。MERGE表的优点在于可以突破对单个MyISAM表的大小限制,并且通过将不同的表分布在多个磁盘上,可以有效的改善MERGE表的访问效率。这对于存储诸如数据仓储等VLDB环境十分合适。

备份的角度

  • 如果可以定期关闭服务器进行备份的话,那可以忽略。反之,如果需要在线热备份,那么选择InnoDB是最基本的要求。

🍙总结

  1. 逻辑架构,分层次能够让我们更好的定位到bug所在之处,高性能的热插拔更是MySQL的独特点所在。
  2. 存储引擎是基于表的,而不是基于库的,可以通过命令查看和修改存储引擎。
  3. 没有特殊需求,我们都选择InnoDB,除非:
    1. 需要全文索引,只有MyISAM支持,但我们还是尽量选择其他可行的方案,比如在InnoDB的基础上去加一些第三方工具或引擎。
    2. 插入和查询操作为主,其他操作几乎很少的业务情况。
  4. InnoDB好MyISAM的区别,面试可能会问到,需要注意一下。
  5. 其他的存储引擎,了解了解即可。

💠下篇预告

这篇我们主要只是总览了逻辑架构和存储引擎,而没有深入涉及具体的知识点,比如MVCC阿,事务隔离级别,锁机制等,这些,我们留到下一篇,来好好聊一聊,这一块的知识点,也是重中之重!!

🖨参考文献

  • 黑马MySQL高级篇

收藏=白嫖,点赞+关注才是真爱!!!本篇文章如有不对之处,还请在评论区指出,欢迎添加我的微信,一起交流:Melo__Jun

🧿友链