这或许是MySQL基础面试题总结最全的一次
2024-10-28 09:03 阅读(179)

Mysql架构与内部模块

演示环境: MySQL 5.7 存储引擎:InnoDB

一、一条查询SQL是如何执行的?


客户端/服务器


程序或者工具要操作数据库,第一步跟数据库建立连接。

通信协议


MySQL必须要运行一个服务,监听默认的端口(3306)。支持多种通信协议:


TCP/IP协议:编程语言的连接模块都是用TCP协议连接到MySQL服务器的。

Unix Socket:在Linux服务器,不用通过网络协议,可连接到MySQL服务器,需用到服务器上的一个物理文件(mysql.sock)。

还有命名管道(Named Pipes)和内存共享(Share Memory)的方式。



MySQL使用半双工的通信方式,意味着要么是客户端向服务端发送数据,要么是服务端向客户端发送数据,这两个动作不能同时发生。所以客户端发送SQL语句给服务端的时候,(在一次连接里面)数据是不能分成小块发送的,如果发送给服务器的数据包过大,需调整MySQL服务器配置max_allowed_packet参数的值(默认是4M)。服务端也是一次性发送所有的数据。



连接方式


MySQL既支持短连接,也支持长连接。短连接就是操作完毕以后,马上close掉。长连接可以保持打开,后面的程序访问的时候还可以使用这个连接。长时间不活动的连接,MySQL服务器会断开。默认的最大连接数是151个(5.7版本),最大是16384(2^14)。





查询缓存(Query Cache)


MySQL内部自带了一个缓存模块,默认是关闭的。主要是因为MySQL自带的缓存的应用场景有限,要求SQL语句必须一模一样,且表里面任何一条数据发生变化的时候,这张表所有缓存都会失效。在MySQL 5.8中,查询缓存已经被移除了。



语法解析和预处理(Parser & Preprocessor)


对SQL语句进行词法和语法分析和语义的解析。

词法解析:把一个完整的SQL语句打碎成一个个的单词。

语法解析:对SQL做一些语法检查,根据MySQL定义的语法规则,根据SQL语句生成一个数据结构,叫解析树。

预处理器(Preprocessor):检查生成的解析树,解决解析器无法解析的语义,比如检查表和列名是否存在等。



查询优化(Query Optimizer)与查询执行计划


查询优化器的目的


根据解析树生成不同的执行计划,然后选择一种最优的执行计划,MySQL里面使用的是基于开销(cost)的优化器。



如何查看优化器工作


启用优化器的追踪(默认是关闭的),执行一个SQL语句,优化器会生成执行计划,可查询相关系统表查看分析过程及结果,查看完之后要关闭它。



优化器能处理的优化类型


比如多表关联查询时基准表的选择,条件过滤顺序,恒等或恒不等等式的处理,能否从索引取数据等。



执行计划


优化器最终会把解析树变成一个查询执行计划,是一个数据结构。可通过在SQL语句前面加上EXPLAIN查看执行计划的信息。





存储引擎(Storage Engine)


基本介绍


在关系型数据库里面,数据是放在表里面的,表的存储结构由存储引擎决定,也可把存储引擎叫做表类型。MySQL支持多种存储引擎,是插件式的。不同的存储引擎通过提供不同的存储机制、索引方式、锁定水平等功能,来满足不同的业务需求。



查看存储引擎


查看数据库表的存储引擎可使用show table status from \training`;`命令。创建表时可指定存储引擎,创建表之后还可以修改存储引擎。



常见存储引擎比较


MyISAM:5.5版本之前默认的存储引擎,表级锁定,不支持事务,拥有较高的插入和查询速度,存储了表的行数,适合只读之类的数据分析的项目。

InnoDB:5.5版本之后默认的存储引擎,支持事务,支持外键,支持行级别的锁和表级别的锁,支持读写并发,写不阻塞读,特殊的索引存放方式,可以减少IO,提升查询效率,适合经常更新的表,存在并发读写或者有事务处理的业务系统。

Memory:将所有数据存储在RAM中,读写速度很快,但数据库重启或者崩溃,数据会全部消失,只适合做临时表,默认使用哈希索引。

CSV:表实际上是带有逗号分隔值的文本文件,不允许空行,不支持索引,格式通用,可以直接编辑,适合在不同数据库之间导入导出。

Archive:用于存储和检索大量很少引用的历史、存档或安全审计信息,不支持索引,不支持update delete。





执行引擎(Query Execution Engine),返回结果


执行引擎利用存储引擎提供的相应API来完成对存储引擎的操作,最后把数据返回给客户端,即使没有结果也要返回。




二、MySQL体系结构总结


架构分层


总体上可把MySQL分成三层:


连接层:管理连接,权限验证。

服务层:包括词法分析,语法分析,执行计划生成,索引选择,操作引擎,返回结果。

存储引擎层:InnoDB、MyISAM等存储数据,提供读写接口。





各模块功能


Connector(连接):管理需要缓冲的资源等。

SQL Interface:用来接收用户的SQL命令,返回用户需要的查询结果。

Parser:用来解析SQL语句。

Optimizer:查询优化器。

Cache and Buffer:查询缓存及其他缓存。

Pluggable Storage Engines:插件式存储引擎,提供API给服务层使用。




三、一条更新SQL是如何执行的?


基本流程


也要经过解析器、优化器的处理,最后交给执行器。区别在于拿到符合条件的数据之后的操作。



InnoDB中的操作


InnoDB里面有个内存的缓冲池(buffer pool),对数据的更新先写入到buffer pool里面,内存的数据页和磁盘数据不一致的时候叫脏页。InnoDB有专门把buffer pool的数据写入到磁盘的线程,叫刷脏。

为了保证数据的持久性,InnoDB引入了redo log(重做日志),记录对内存数据的修改操作,如果服务器出问题,从这个日志文件里面读取数据恢复数据。MySQL Server层也有一个日志文件binlog,以事件的形式记录了所有的DDL和DML语句,可用来做主从复制和数据恢复。



更新语句执行流程示例


以update user set name='jim'where name='666';为例:


先查询到这条数据,如果有缓存,也会用到缓存。

把name改成jim,然后调用引擎的API接口,写入这一行数据到内存,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成了,可以随时提交。

执行器收到通知后记录binlog,然后调用存储引擎接口,设置redo log为commit状态。

更新完成。





两阶段提交(XA)的原因


如果只写redo log,没写bin log时MySQL重启,会出现数据不一致的情况,所以在写两个日志的情况下,binlog充当事务的协调者,通知InnoDB来执行prepare或commit或者rollback。




四、MySQL索引原理详解


索引是什么?


是数据库管理系统(DBMS)中一个排序的数据结构,以协助快速查询、更新数据库表中数据。

索引类型


普通(Normal):也叫非唯一索引,没有任何的限制。

唯一(Unique):要求键值不能重复,主键索引是特殊的唯一索引,要求键值不能为空。

全文(Fulltext):针对比较大的数据,只有文本类型的字段才可以创建全文索引。





索引存储模型推演


二分查找:可考虑用有序数组作为索引的数据结构,但更新数据时会有问题,所以引入链表,又因为单链表查找效率不够高,诞生了二叉查找树(BST)。

二叉查找树(BST Binary Search Tree):特点是左子树所有的节点都小于父节点,右子树所有的节点都大于父节点,但在最坏情况下时间复杂度会退化成O(n)。

平衡二叉树(AVL Tree)(左旋、右旋):左右子树深度差绝对值不能超过1,通过左旋和右旋操作保持平衡,可作为索引结构,但存在节点存储数据少导致磁盘交互次数多的问题。

多路平衡查找树(B Tree)(分裂、合并):分叉数(路数)永远比关键字数多1,通过分裂和合并操作保持平衡,检索效率比AVL树高。

B+树(加强版多路平衡查找树):是B Tree的变种,关键字的数量是跟路数相等的,根节点和枝节点中都不会存储数据,只有叶子节点才存储数据,每个叶子节点增加了一个指向相邻叶子节点的指针,具有扫库、扫表能力更强,磁盘读写能力更强,排序能力更强,效率更加稳定等优势。

索引方式:在Navicat工具中,创建索引方式有HASH和B+Tree等,HASH索引有查询速度快但不能用于排序、只能支持等值查询、字段重复值多时效率会降低等特点,InnoDB中不能显示地创建一个哈希索引,Memory存储引擎可以使用Hash索引。



B+Tree落地形式


MyISAM:索引和数据是两个独立的文件,在B+Tree里面,叶子节点存储的是数据文件对应的磁盘地址。

InnoDB:以主键为索引来组织数据的存储,索引文件和数据文件是同一个文件,都在.ibd文件里面,主键索引的叶子节点上直接存储了数据,其他索引检索数据时需先找到主键值再到主键索引叶子节点拿数据。



索引使用原则


列的离散(sàn)度:列的重复值越多,离散度就越低,不建议在离散度低的字段上建立索引。

联合索引最左匹配:联合索引在B+Tree中是复合的数据结构,按照从左到右的顺序来建立搜索树,建立联合索引时要把最常用的列放在最左边,查询条件没有最左边的列时用不到索引。

覆盖索引:非主键索引先通过索引找到主键索引的键值,再通过主键值查出索引里面没有的数据叫回表,如果select的数据列只用从索引中就能够取得,不必从数据区中读取,这时候使用的索引就叫做覆盖索引,可提升查询效率。



索引的创建与使用


在什么字段上索引?


在用于where判断order排序和join的(on)字段上创建索引,索引的个数不要过多,区分度低的字段不要建索引,频繁更新的值不要作为主键或者索引,随机无序的值不建议作为主键索引,创建复合索引而不是修改单列索引。



什么时候索引失效?


索引列上使用函数、表达式计算,字符串不加引号出现隐式转换,like条件中前面带%,负向查询(部分情况),这些情况可能导致索引失效,最终是否使用索引由优化器说了算,优化器是基于cost开销的优化器。






五、MySQL性能优化思路和工具


优化思路


从客户端连接、缓存、解析器、优化器、存储引擎等环节入手优化。



连接--配置优化


服务端


可增加服务端的可用连接数,修改max_connections的大小,及时释放不活动的连接。



客户端


可减少从服务端获取的连接数,引入连接池,如ORM层面或使用专用的连接池工具。





缓存--架构优化


缓存


可引入第三方的缓存服务如Redis来减少数据库压力。



主从复制


主从复制可实现数据一致性,通过binlog实现,涉及I/O线程、log dump线程和SQL线程。可实现读写分离,减轻数据库服务器的访问压力。



分库分表


垂直分库减少并发压力,水平分表解决存储瓶颈。





优化器--SQL语句分析与优化


慢查询日志slow query log


打开慢日志开关,可设置执行超过多长时间的SQL才记录到慢日志,可通过mysqldumpslow工具分析慢查询日志。



SHOW PROFILE


可查看SQL语句执行的时候使用的资源,如CPU、IO的消耗情况。



EXPLAIN执行计划


通过EXPLAIN可模拟优化器执行SQL查询语句的过程,分析语句或者表的性能瓶颈,EXPLAIN的结果有很多字段,可从id、select_type、type等多个方面分析。





存储引擎


存储引擎的选择


为不同的业务表选择不同的存储引擎,如查询插入操作多的业务表用MyISAM,临时数据用Memory,常规的并发大更新多的表用InnoDB。



字段定义


原则是使用可以正确存储数据的最小数据类型,如整数类型选择合适的字节数,字符类型根据情况选择char或varchar,不要用外键、触发器、视图,大文件不要用数据库存储,可考虑表拆分或字段冗余。





总结:优化体系


从SQL与索引、存储引擎与表结构、数据库架构、MySQL配置、硬件与操作系统等维度优化,同时业务层面的优化也不能忽视。