MySQL
的我又回来啦!虽然迄今为止我的面试大写着失败,但这并不妨碍我继续失败!48
码的大头上,渐渐取下了一顶假发帽,露出了在阳光下略带反光的地中海!该死,这气息的压迫感....好强大!Java、Golang、Rust、PHP、Scala、C/C++、Spring、Redis....MySQL
等技术栈的单词拼写!MySQL
?好,那我接下来考考你。MySQL
单词的拼写......MySQL
底层架构哈。SQL
解析、结果合并、执行计划生成等。MySQL
较为重要的一层,服务层主要是制定执行计划和等待结果,但读写数据的具体操作都需要通过引擎层来完成,引擎层决定着表数据读写方式和存储方式。MySQL
的基础层,对上层服务提供最基础的文件服务,如日志、数据、索引等文件的支持。
MySQL
服务建立连接的呢?TCP/IP
的三次握手过程,如果采用了加密连接的方式,还会经过SSL
的握手过程,握手完成后MySQL
和客户端会建立session
连接。MySQL
会查询自身的mysql.user
表,来验证客户端的用户名和密码,如果有误则会报错。MySQL
成功建立连接之后,MySQL
会先保存客户端的网络连接信息,即session
会话信息。SQL
语句时,维护对应连接的线程则会去执行,执行过程中也会由对应的线程处理结果集并返回。SQL
语句后,MySQL
默认会将连接维护八小时,在这八小时内不会销毁,除非客户端主动发送了quit
指令,这时MySQL
才会主动销毁连接,但这里的销毁也并非真正意义上的销毁。MySQL
只会将对应线程绑定的会话信息清空,然后将“空闲”的线程放入自身的连接池当中,以备下次客户端连接时使用。SQL
语法是否正确。SQL
执行的最优方案,如选择合适的索引、选择合适的join
方式等,对于优化器最终选择的执行计划可以通过explain
工具来查看。MySQL
执行是如何执行一条SQL
语句的呢?SQL
发送给SQL
接口,SQL
接口会对SQL
语句进行哈希处理。SQL
接口在缓存(QueryCache
)中根据哈希值检索数据,如果缓存中有则直接返回数据。SQL
交给解析器,解析器会判断SQL
语句是否正确:
1064
错误码及相关的语法错误信息。SQL
语句交给优化器处理,进入第④步。SQL
制定出不同的执行方案,并择选出最优的执行计划。API
获取数据。API
调用方的操作,去磁盘中检索数据(索引、表数据....)。IO
后,对于磁盘中符合要求的数据逐条返回给SQL
接口。SQL
接口会对所有的结果集进行处理(剔除列、合并数据....)并返回。SQL
发送给SQL
接口,SQL
接口会对SQL
语句进行哈希处理。SQL
交给解析器,解析器会判断SQL
语句是否正确:
1064
错误码及相关的语法错误信息。SQL
语句交给优化器处理,进入第④步。SQL
制定出不同的执行方案,并择选出最优的执行计划。undo-log
日志和redo-log(prepare状态)
日志。API
。IO
,读取磁盘中的数据做写操作。bin-log
日志,同时将redo-log
日志中的记录改为commit
状态。SQL
执行耗时及操作成功的结果返回给SQL
接口,再由SQL
接口返回给客户端。8.0
之后的版本中想开也开不了,因为被移除了。MySQL
的查询缓存就一言难尽,有多方面原因吧,如下:
SQL
都无法从查询缓存中获得数据。MB
的内存。LRU
算法淘汰缓存,同时每次更新/插入/删除数据时,都要清空缓存中对应的数据。MyISAM
引擎设计的,而InnoDB
构建的缓冲区完全具备查询缓存的作用。Redis
做业务缓存,能来到MySQL
查询的语句十有八九是要走磁盘的,因此查询缓存的存在,反而弊大于利。SQL
执行流程,那你能不能跟我说一下SQL
执行之前会发生什么呢?SQL
语句的诞生,都源自于平台用户的操作,用户发送的请求最终会转变为一条条具体的SQL
语句。SQL
之后接着会去配置好的数据库连接池,如Druid
中获取一个数据库连接,然后发给MySQL
执行,但执行前还会先判断当前连接的用户,是否具备SQL
要操作的表权限。Druid
这类连接池,和MySQL
自己维护的连接池,会不会冲突呢?TCP
三次握手、四次挥手、SSL
握手等过程。SQL
执行时,光网络握手和创建线程就需要耗费不少时间。SQL
语句,也就意味着同一时间可以处理更多的用户请求,但理想很丰满,现实很骨感,由于硬件配置的原因,这种做法是不行的。100
,这也意味着应用程序和MySQL
各自都需要开启100
条线程维护这些连接。OS
只能频繁的在每条线程之间切换CPU
资源,确保每条线程能够正常运转。CPU
资源的总时长,反而会超出实际执行SQL
的时间,所以根据机器的硬件来配置最大线程数,这才是最合理的方案,目前业界主流的配置计算公式为:CPU
核心数*2
,如果硬盘材质是SSD
的,那么还可以再加个一,这属于最佳配置。MySQL
一条线程执行完成后,它是如何知道自己该向谁返回数据的?IP
地址、端口等信息,当一条线程执行完成后,只需要根据这个地址去封装数据报文就好啦,如果要返回的结果集比较大,MySQL
会把一个大的数据包拆分成多个小的数据报文分批返回。MySQL
是如何从磁盘中按条件读取数据的吗?MySQL
会默认会触发磁盘IO
来读取表数据,但InnoDB
引擎读取时,会利用局部性原理,也就是预读思想,一次IO
会读取16KB
磁盘数据放入内存,接着和SQL
语句的条件做对比,符合条件的留在内存,其他的丢弃,然后继续去磁盘中读其他的表数据,直到把整张表的数据文件都找一次后,最后才会把符合条件的数据返回,这个过程也被称作全表扫描。MySQL
查数据,怎么才能更快一点。MySQL
中也有索引,我们可以在经常查询的字段上创建索引,查询时就能直接走索引查找了。MySQL
中有哪些索引呢?Hash
索引、B+Tree
索引、R-Tree
索引、T-Tree
索引。like
模糊查询,你有好办法优化不?ES
这类搜索引擎来完成模糊查询工作,如果不想用,则可在对应字段上建立全文索引,全文索引会比like
查询的效率更高,并且支持全模糊、左模糊查询走索引。MySQL
索引的底层是什么数据结构么?Hash、B+Tree
两种结构,通常是B+
树。IO
,索引树的树高决定着磁盘IO
的次数,磁盘IO
的次数越多,意味着查询耗时、资源开销会更大,所以您所提及到的这些树结构,并不适合作为索引结构的实现。B
树结构也不合适呢?它单个叶子节点不是会存储多个数据吗?B
树结构,各个叶子节点之间没有指针连接,所以对于范围查询支持不友好。B+
树则不同,每个叶子节点都会有一根指向下个节点的指针,范围查询时可以基于这些指针快捷查找。MySQL
也并未选择传统的B+Tree
结构来实现索引,而是又对其进行了改良,毕竟B+
树只有指向下个节点的指针,所以只支持正向范围查询,而不支持反向范围查询。MySQL
在传统的B+Tree
结构中,又在每个节点中加了一个指向上个节点的指针,这样做之后也支持反向范围查询。MySQL
索引用了变种B+Tree
咯?再问一下你们项目一般选什么字段作为主键?ID
字段作为主键。B
树的问之外,心里最好也要有个B
树。InnoDB
引擎的非聚簇索引和传统的非聚簇索引不同,例如MyISAM
引擎中的非聚簇索引,索引值存储的是行数据的磁盘地址。InnoDB
的非聚簇索引的索引值,因为表数据和聚簇索引键存储在一起,存储的则是对应行数据的聚簇索引键。InnoDB
引擎独有的坏毛病,基于非聚簇索引/次级索引查找数据时,从索引中查找索引值后,会接着再通过查到的聚簇索引键再查一次聚簇索引,从而得到最终需要的行数据。*
来表示所有字段,这样可以重复利用索引覆盖机制来获取数据,从而减少回表查询的次数。MySQL
的一种优化手段,假设通过name、sex、age
三个字段建立了一个联合索引,当基于联合索引查询时只需要返回name、age
,因为这两个字段值在联合索引中都包含了,那就可以直接从索引键中读取数据返回。*
时,因为联合索引中不具备完整数据,所以只能触发回表动作得到完整的行数据。........
B+Tree
:对索引字段的值进行排序,按照顺序组成B+
树结构。Hash
:对索引字段的值进行哈希计算,处理相应的哈希冲突,方便后续查找。.......
InnoDB
主键索引:对.ibd
文件中的表数据进行重构,将索引键和行数据调整到一块区域中存储。InnoDB
次级索引:因为有聚簇索引,将非聚簇索引的索引值,与行数据对应的聚簇索引键的关联起来。MyISAM
:由于表数据在单独的.MYD
文件中,因此可以直接以磁盘指针的关联表数据。SQL
条件比它大,会去继续读取右边的叶节点,反之则读取左边的叶节点,然后再进行判断。InnoDB
聚簇索引:直接从索引树中得到行数据,因为行数据和聚簇索引存储在一块。InnoDB
次级索引:看是否能够使用索引覆盖机制获取数据,不行则触发回表动作得到数据。MyISAM
的索引:根据索引键中记录的磁盘地址,直接去磁盘中读取行数据。ascii
码),计算出一个位置并插入。A、B、C
三个字段组成,那么在写SQL
语句时,最好按照索引字段的顺序来使用索引,如果写的SQL
中不包含第一个A
字段,一般都无法使用这个联合索引查询数据。A、C
字段,但没有使用B
字段,也无法完全利用联合索引。MySQL
的联合索引会从左往右匹配数据,所以在设计索引时,最好把查询频率高的字段放在前面,这样才能充分利用最左匹配原则查询数据,但MySQL8.0
中也推出了一种名为索引跳跃式扫描的机制,可以打破联合索引的最左匹配原则查找数据。MySQL
索引除开索引覆盖、跳跃扫描外,还有别的优化机制吗?MySQL5.6
中引入的索引下推机制、MRR机制,这两种机制能够在很大程度上减少索引查询的磁盘IO
,以及离散性的磁盘IO
。SQL
语句使用索引,先来说说什么是合理的创建索引:
Hash
结构。3
,最多不能超过5
。SQL
语句时的注意点,主要是避免索引失效即可,索引失效的场景有下面这些情况:
SQL
语句的时候,可以刻意避开这些会导致索引失效的场景即可。SQL
查询的分组和排序的时间。B+Tree
有序结构,基于索引字段做范围查询时,效率会明显提高。MySQL
整体架构而言,减少了查询SQL
的执行时间,提高了数据库整体吞吐量。SQL
时效率会降低,性能会下降。A
账户余额、加B
账户余额这两个操作组成,假设现在扣完A
的余额后,结果程序执行时抛Bug
了,但此时B
的余额还没有增加,这最终会造成A
账户的钱平白无故消失了!所以也正因如此,才需要事务机制来确保一组操作的数据一致性。ACID
原则,则是数据库事务机制要满足的四个特性:
A/Atomicity
:原子性,指组成一个事务的一组SQL
要么全部执行成功,要么全部执行失败。C/Consistency
:一致性,指任何一个事务发生的前后,库中的数据变化必须一致。I/Isolation
:独立性/隔离性,指同时存在多个并发事务时,各个事务之间执行的操作不会相互影响。D/Durability
:持久性,指一个事务但凡提交之后,就必须确保事务变更过的数据永远不会丢失。MySQL
的事务隔离级别有四个,每个级别分别能够解决不同的问题,如下:
RU
:处于该隔离级别的数据库,脏读、不可重复读、幻读问题都有可能发生。RC
:该级别中解决了脏读问题,不可重复读、幻读问题依旧存在。RR
:该级别中解决了脏读、不可重复读问题,幻读问题依旧存在。Serializable
:该级别中解决了脏读、不可重复读、幻读问题都不存在。MySQL-Server
本身没有提供事务机制,事务机制是InnoDB
引擎独有的特性,而事务机制是基于Undo-log
日志实现的,InnoDB
默认会开启事务的自动提交,将每条SQL
都视作一个单独的事务,而通过begin
开启事务后,需要手动提交后才能生效,可以将多条SQL
语句组成一个事务。Undo-log
日志,更新数据前,会把原本的老数据放到Undo-log
日志中,然后在表的数据行上记录一个回滚指针,这个指针会指向Undo-log
中的旧数据。InnoDB
会直接根据回滚指针的地址,找到原本的老数据,然后直接复制过来,将变更过的新数据覆盖掉。MDL
锁:基于表的元数据加锁,加锁后整张表不允许其他事务操作。InnoDB
中为了支持多粒度的锁,为了兼容行锁、表锁而设计的。AUTO-INC
锁:这个是为了提升自增ID的并发插入性能而设计的。Record
锁:也就是行锁,一条记录和一行数据是同一个意思。Gap
锁:InnoDB
中解决幻读问题的一种锁机制。Next-Key
锁:间隙锁的升级版,同时具备记录锁+间隙锁的功能。S
锁:不同事务之间不会相互排斥、可以同时获取的锁。X
锁:不同事务之间会相互排斥、同时只能允许一个事务获取的锁。SX
锁:MySQL5.7
版本中新引入的锁,主要是解决SMO
带来的问题。DDL
语句时使用的锁。SQL
语句时,手动指定加锁的粒度。SQL
语句时,根据隔离级别自动为SQL
操作加锁。MySQL
的表锁、行锁有哪些呢?MySQL
中是InnoDB
引擎独有的,并且InnoDB
的行锁和表锁之间,是相互兼容的。InnoDB
的行锁默认就是临键锁类型,这三种锁都属于InnoDB
的行锁算法,InnoDB
会根据情况来选择不同的行锁算法获取锁。MySQL
的时候似乎没有使用呀?MySQL
在执行语句时,自动根据情况来加的锁,因此也被称之为隐式锁,但我们也可以在SQL
语句中,通过for update、for share
这种语法手动加锁。MySQL
自动完成的,但不同事务隔离级别中,释放锁的时机也不同,如果目前是读未提交级别,MySQL
执行完一条语句后就会立马释放锁。如果是其他级别中,基本上都需要等待持有锁的事务结束(commit/rollback
)后才会释放。SMO
问题,共享排他锁主要就是用来解决SMO
问题。A、B、C
用户看到后开始阅读这篇新闻。A、B、C
用户正在看新闻呀!肯定不能直接给它们显示一个审核中的状态,所以就会采用多版本方案,新版本进入审核状态,而用户则读老版本的新闻。MVCC
机制翻译过来也就是多版本并发控制技术,是InnoDB
中用来解决读-写事务并发冲突问题的,对于多事务并发执行的情况下,InnoDB
引擎的表在更新某条数据时,并不会阻塞尝试读取这条数据的事务,而是会让读数据的事务去拿更新前的数据记录,和前面我给您的举例类似,从而实现了读写事务并发执行。MVCC
机制是通过Undo-log
日志的版本链、数据表上的隐藏字段、以及ReadView
读视图实现的,简单来说就是:写操作会直接对表数据进行变更,而读操作会根据回滚指针,去找到Undo-log
中的旧数据读取。MySQL
锁机制是基于事务实现的,一个事务尝试获取锁时,就会在内存中生成一个锁结构,锁结构中会记录着当前事务,要加锁的数据地址,会精确到表空间、数据段、数据页、行数的信息。同时锁结构中有一个is_waiting
信息,为0
表示当前锁结构对应事务持有着锁,而为1
表示当前锁结构对应的事务在阻塞等待获取锁。is_waiting=1
。MVCC
机制实现的,如下:
RU
:写操作加排他锁,读操作不加锁。RC
:写操作加排他锁,读操作使用MVCC
,但每次select
都生成读视图。RR
:写操作加排他锁,读操作依旧采用MVCC
机制,但一次事务中只生成一个读视图。Serializable
:所有写操作加临键锁(具备互斥特性),所有读操作加共享锁。........
因为今晚临时有事,所以得出去一趟,目前这章大概有
1.2W
字,全部写完预计会有3~4W
字左右,我忙完之后会回来继续更,诸位对后续内容感兴趣,可点个关注或收藏,耐心等待一小会儿时间~(时间也不会太久,大概明后天左右会彻底更完!本章属于整个MySQL
专栏的总结篇,所以写起来速度会比较快,抛开事实不谈的情况下,日更十万字简直不在话下,哈哈哈)
MySQL
的日志熟悉么?MySQL
中的日志种类不少,但常用的主要有六种:
Undo-log
撤销日志:当有操作变更数据前,都会把老数据放入该日志中。Redo-log
重做日志:该日志记录着InnoDB
所有表的变更语句,也可用来做灾难恢复。Bin-log
变更日志:这里面记录着所有对数据库会产生变更的语句。Error-log
错误日志:记录着MySQL
启动、运行期间所有的报错、警告信息。Slow-log
慢查询日志:记录着所有执行时长超出指定阈值的查询语句。Relay-log
中继日志:主从集群中,丛节点用于存储主节点Bin-log
数据的日志。Bin-log
日志还需要Redo-log
日志呢?Redo-log
是InnoDB
引擎独有的日志,主要功能在于做灾难恢复,每条写入语句在执行前,都会先记录一条prepare
状态的日志,然后再执行SQL
语句,执行完成后会记录bin-log
日志,接着再把Redo-log
日志的状态从prepare
改为commit
。如果一个事务提交后,数据在内存中还未刷盘,此时MySQL
宕机了,后续重启时也可以根据Redo-log
来恢复数据。Redo-log、Bin-log
两者的区别,主要可以从四个维度上来说:
Redo-log
是InnoDB
专享的,Bin-log
是所有引擎通用的。Redo-log
是用两个文件循环写,而Bin-log
是不断创建新文件追加写。Redo-log
中记录的都是变更后的数据,而Bin-log
会记录变更SQL
语句。Redo-log
主要实现故障情况下的数据恢复,Bin-log
则用于数据灾备、同步。MySQL、InnoDB
专门在内存中设计了日志缓冲区,不同日志有不同的缓冲区,日志也是先写内存,然后由后台线程来完成刷盘。Redo-log、Bin-log
日志的刷盘机制了解过么?redo-log
日志的刷盘策略由innodb_flush_log_at_trx_commit
参数控制,而bin-log
日志的刷盘策略则可以通过sync_binlog
参数控制:
innodb_flush_log_at_trx_commit
:
0
:间隔一段时间,然后再刷写一次日志到磁盘(性能最佳)。1
:每次提交事务时,都刷写一次日志到磁盘(性能最差,最安全,默认策略)。2
:有事务提交的情况下,每间隔一秒时间刷写一次日志到磁盘。sync_binlog
:
0
:同上述innodb_flush_log_at_trx_commit
参数的2
。1
:同上述innodb_flush_log_at_trx_commit
参数的1
,每次提交事务都会刷盘,默认策略。Bin-log
日志格式有哪些呢?Statment
:记录每一条会对数据库产生变更操作的SQL语句(默认格式)。Row
:记录具体出现变更的数据(也会包含数据所在的分区以及所位于的数据页)。Mixed
:Statment、Row
的结合版,可复制的记录SQL语句,不可复制的记录具体数据。bin-log
日志是按顺序追加写,一个日志文件满了之后,会创建一个新的日志文件来存放记录,在本地会呈现bin-log.0001、bin-log.0002、bin-log.000x.....
这种形式,所以咱们只需要找到误删命令执行前的日志文件,然后通过日志来恢复数据即可。bin-log
前写入日志,可能会导致主从集群数据同步不一致,但如果放在bin-log
后写入日志,则无法实现灾难恢复,所以被设计成了在bin-log
前后都写入一次。long_query_time
参数指定时间阈值,MySQL
会自动将超出阈值的查询语句记录进去。MySQL
是基于磁盘工作的,你对此怎么看呢?MySQL
在设计的时候的确是基于磁盘工作,但因为MySQL
的存储引擎支持可拔插式,所以如果库使用的是InnoDB
引擎,这时情况就不同了。InnoDB
会在内存中构建出一个BufferPool
缓冲区,只要为其分配的内存足够大,InnoDB
基本上会把所有操作都放在内存中完成。InnoDB
构建出的缓冲区,会把内存划分为一个个的「页」,每个页的默认大小为16KB
,以页作为内存和磁盘交互的基本单位,这些缓冲页会分为三种:
InnoDB
可以基于控制块去管理每一块缓冲页。InnoDB
会基于三个链表来管理所有缓冲页,所有缓冲页会根据类型不同,分别加入到不同的链表中,每个缓冲页通过控制块中的指针,形成逻辑连续的链表结构:
Free List
:负责记录空闲页,为了使用时能更快的找到空闲缓冲页。
Lru List
:记录所有已经使用过的缓冲页,为了方便淘汰已使用的内存页。Flush List
:负责记录所有变更页,为了刷盘时能够更快的找到变更数据页。
Lru
链表移动到Flush
链表中。Flush
链表中移回Lru
链表。OOM
内存溢出,所以有些数据页会被淘汰出内存。Lru
链表了,InnoDB
会采用末尾淘汰机制,这正如大部分企业中推行的KPI
绩效机制类似,每个员工都会有KPI
绩效,到了年底时会淘汰一部分绩效较低的员工,来年后再招聘新员工,吸收新鲜血液入职。InnoDB
中也类似,所有使用过的数据页都会加入Lru
链表中,但每当一个数据页被访问后,都会将其移动到链表的最前面,这样就能够保证热度较高的数据页长久留在内存中,及时淘汰掉那些热度较低的数据页。1~2
次的数据,岂不是需要很久才能被淘汰吗?InnoDB
把Lru
链表分为了young、old
两个区域,默认比例为63:37
:
young
区域:存放经常被访问的热点数据页。old
区域:存放刚从磁盘中加在的数据页。LRU
链表被划分为两个区域后,从磁盘中预读的数据页会加入到old
区域的头部,当这个数据页被真正访问时,才会将其插入young
区的头部。old
区域移除,从而不会影响young
区域中的热点数据。old
区域,而想要从old
移到young
区域,这是有晋升限制的。old
晋升到young
区,必须要在old
区中存活一定时间,这个时间默认为1000ms
。old
进入young
区的条件,数据页想从Old
转到Young
得满足两个条件:
old
区中停留的时间超过了1000ms
。old
区中,一秒后有线程再次访问了这个数据页。InnoDB
内部的执行过程吧。InnoDB
在处理读写语句时也会有细微差距:
SQL
语句,将目标数据从磁盘载入内存,经过条件筛选后返回。insert
新增操作呢?之前磁盘没有数据呀,如何处理呢?InnoDB
有一个插入缓冲区,5.6
之后叫做写入缓冲区,专门用来处理新增操作,insert
的数据会被放到这个缓冲区中,然后由后台线程完成刷盘工作。InnoDB
的自适应哈希索引吗?Hash
结构是所有数据类型中最快的,所以InnoDB
会在运行期间,统计出一些经常走索引查询的热点数据,然后针对这些热点索引数据,去为其建立哈希索引,以此提升查询性能。MySQL
内存中有什么?MySQL
常用的InnoDB、MyISAM两款引擎之间的区别吧。MyISAM
引擎的表会生成三个磁盘文件:
table_name.frm
:该文件中存储表的结构信息。table_name.MYD
:该文件中存储表的行数据。table_name.MYI
:该文件中存储表的索引数据。InnoDB
引擎的表只会生成两个磁盘文件:
table_name.frm
:该文件中存储表的结构信息。table_name.ibd
:该文件中存储表的行数据和索引数据。InnoDB
支持聚簇索引,而MyISAM
只支持非聚簇索引,因为它索引数据和表数据是分开存储的。InnoDB
基于Undo-log
日志实现了事务机制,但MyISAM
没有,所以不支持事务。InnoDB
基于Redo-log
日志实现了故障恢复机制,但MyISAM
则只能依靠Bin-log
,因此会有丢失数据的风险。InnoDB
可以基于聚簇索引实现行锁,同时还兼容表锁,但MyISAM
仅支持表锁。InnoDB
因为支持行锁以及MVCC
机制,所以并发场景下的性能会远超MyISAM
引擎。InnoDB
由于设计了BufferPool
缓冲池,所有内存利用度会远超MyISAM
引擎。SQL
语句。SQL
被暴露的风险。CPU
开销大:如果其中涉及大量逻辑运算工作,会导致MySQL
所在的服务器CPU
飙升。Debug
调试,出错时难以排查。AOP
切面的话怎么实现呢?MySQL
的触发器来完成,insert、delete、update
三个操作都可以添加前/后置处理器,效果与AOP
切面类似。SQL
语句,不想用定时调度框架怎么办呢?MySQL
的定时器,支持按年、季、月、周、日、时、分、秒、毫秒等精度触发。SQL
时,经常会用那些语句、关键字、和函数呢?......
,我给你一个命令大全,您自己看吧。MySQL
的性能优化可以从五个维度来说:
DB
连接池的参数和DB
连接层的参数。MySQL
架构提高可用性。SQL
语句,提高索引命中率。CPU
核心数*2
,如果硬盘材质是SSD
的,那么还可以再加个一,总的来说就是根据硬件来配置。MySQL
呢?MySQL
只有一个应用程序访问,在客户端配好最大连接数就行,如果提供给多个应用访问,则需要限制一下MySQL
的最大连接数。int
就别用bigint
。NULL
,因为字段空值过多会影响索引性能。N
个字节,创建前缀索引。Hash
结构代替B+Tree
结构。DBA
负责,个人一般就是调大缓冲区、线程缓冲区这些。Redis
做缓存,来减少落入数据库中的读请求,分担大部分读压力。MQ
做削峰,来将并发情况下的写压力,平缓到数据库可承载的级别。SQL
优化,核心就是减小查询的数据量、提升SQL的索引命中率,在写SQL
的时候刻意注意下述一些原则即可:
*
会导致网络开销变大,并且无法利用索引覆盖机制。like
查询以%
号开头会导致索引失效,从而走全表查询。where
字句的=
号前做运算,也会导致索引失效。MySQL
的limit
关键字,处理深分页会把前面的数据都查一次。SQL
解析、优化次数。SQL
时注意上述十六条原则,通常写出的语句,其效率都不会太差。SQL
执行标准是多久呢?200ms
以内,超出这个时间,就会导致客户端长时间无响应。MySQL
前会开启慢查询日志,直接查看慢查询日志即可。explain
工具分析语句,到底是没走索引、还是由于扫描的数据量较大,然后对症下药解决问题。MySQL
中的最大连接数,此时再出现新连接时就会出异常。MySQL
版本不匹配,或超时时间过小,也可能导致出现连接中断。MySQL、Java
程序所部署的机器不位于同一个网段,两台机器之间网络存在通信故障。MySQL
的机器资源耗尽,如CPU
、硬盘过高,导致MySQL
没有资源分配给新连接。MySQL
的机器白名单,及登录的用户IP
限制,可能是IP
不在白名单范围内。MyCat
这类代理中间件,记得检查中间件的白名单、超时时间等配置。MySQL
会有死锁检测机制主动解除已发生的死锁,但无法彻底根治死锁,想要根治必须要先找到频繁触发死锁的事务,步骤如下:
SHOW ENGINE INNODB STATUS\G
命令,查询InnoDB
的运行时日志。LATEST DETECTED DEADLOCK
区域,这其中会记录发生过的死锁。SQL
为何会产生死锁,然后调整即可。CPU
过高的服务器。MySQL
磁盘利用率达到100%
的原因,通常是因为磁盘占用过高导致,占用过高的情况有很多种,如下:
MySQL
整体并发过高,磁盘I/O
频率跟不上,比如是机械硬盘材质,读写速率过慢。BufferPool
缓冲池过小,大量读写操作落入磁盘处理,导致磁盘利用率过高。IO
打满。SSD
材质,请先将磁盘升级成固态硬盘,MySQL
对SSD
硬盘有特殊优化。Redis
降低读压力,引入MQ
对写操作做流量削峰。BufferPool
缓冲池的大小,最好设置成机器内存的70~75%
左右。SQL
语句时尽量减少多张大表联查,不要频繁的使用和销毁临时表。MySQL
各版本的新特性有了解过吗?MySQL5.6、5.7、8.0
这三个重量级版本。MySQL5.6
属于一个里程碑式的版本,在这个版本中性能改善很大,重点有六个改进:
MVCC
机制读取数据的速度。IO
、锁资源、SQL
语句...信息。IO
次数。IO
,并且将随机IO
转换为顺序IO
,从而提高查询效率。GTID
复制、无损复制、延时复制、并行复制技术。5.7
版本中更多是在改善5.6
中的问题,因为优化太多,所以有很多细节需要改进,对于新特性就两个较为重要的:
SMO
问题发生时,锁住整颗B+
树(表锁)影响并发性能。MySQL
表结构支持Json
格式,无需将其转换为字符串再进行存储。MySQL8.0
是改进较大的一个版本,其中发生的变更比较多,主要也有七点:
8.0
中会持久化到本地。SQL
编程的灵活性。MySQL
的特性支持。Nest-Loop-Join
嵌套循环连接算法,而8.0
中,在适当情况下会选择Hash-Join
算法提升查询性能。Nest-Loop-Join
嵌套循环连接算法,自己有深入了解过吗?Nest-Loop-Join
算法执行时,会通过循环嵌套的模式工作,外层循环遍历驱动表的数据,内层循环遍历被驱动表的数据,然后再进行目标数据的检索,最终得到目标数据。Hash-join
算法呢?Nest-Loop-Join
算法执行时,因为采用的是循环嵌套,所以性能方面并不高。Hash-Join
算法效率很高么?=
符号做等值连接查询时的确如此,在哈希算法中会分为构建表和探测表,构建表则是作为条件的表,探测表是需要检索数据的表。MySQL
会对构建表的每行数据生成哈希值,然后最终得到一张哈希表,接着只需要循环探测表的数据,将每条数据计算出哈希值,然后去哈希表中匹配即可。Bin-log
二进制日志。Bin-log
日志的log dump
线程。log dump
线程监听到日志发生变更时,会通知从节点来拉取数据。I/O
线程等待主节点的通知,当收到通知时会去请求一定范围的数据。relay-log
中继日志。relay-log
变更的SQL
线程,当日志出现变更会开始工作。MySQL
主从同步数据时,是主节点推送还是从节点拉取?MySQL
中主从之间的数据复制,支持四种同步方式:
ACK
之前,不会提交事务。① < ④ < ③ < ②
,从数据一致性来说② < ③ < ④ < ①
。5.6
特性时,提到的延迟复制、GTID
复制、并行复制是啥意思?GTID
复制:主从的同步点依靠全局事务ID
来实现,开启后无需人工指定数据同步点。Canal
来监控主机的Bin-log
日志,一发生变化就立马同步数据。SQL
语句该如何执行呢?1~3
个字段,可直接在另一张表中设计冗余字段。ES、Redis
。Java
中作聚合操作,从而得到出最终数据。API
接口获取数据,然后在程序中组装后返回。Seata
框架,内部提供了多种模式支持,思想如下:
Best Efforts 1PC
模式。XA 2PC、3PC
模式。TTC
事务补偿模式。MQ
最终一致性事务模式。ES
或中间表,运行期间跑按时更新其中的分页数据。Service
层再做过滤处理。ID
交叉增长,保证唯一性。ID
,比如Snowflake
雪花算法等。ID
生成器,如使用Redis
的incr
命令、或创建独立的库专门做自增ID
工作。DB1:1~500W、DB2:500~1000W....
。ID
或哈希值与节点数量做取模运算,最终得到数据落入的节点。..........
MyCat
和Apache-Sharding-Sphere
,个人更倾向于后者。Apache-Sharding-Sphere
的工作原理嘛?SQL
解析:SQL
执行时,会先根据配置的数据源来调用对应的解析器,然后对语句进行拆解。SQL
路由:拆解SQL
后会从中得到路由键的值,接着会根据分片算法选择单或多个数据节点。SQL
改写:选择了目标数据节点后,接着会改写、优化用户的逻辑SQL
,指向真实的库、表。SQL
执行:对于要在多个数据节点上执行的语句,内部开启多线程执行器异步执行每条SQL
。SQL
中使用了order by、max()、count()...
等操作,对结果处理后再返回。MyCat
和Apache-Sharding-Sphere
有啥区别呢?Sharding-Sphere
是由Sharding-Porxy、MyCat
两款产品组成的,三者对比如下:对比项 | Sharding-JDBC | Sharding-Proxy | MyCat |
---|---|---|---|
性能开销 | 较低 | 较高 | 高 |
异构支持 | 不支持 | 支持 | 支持 |
网络次数 | 最少一次 | 最少两次 | 最少两次 |
异构语言 | 仅支持Java | 支持异构 | 支持异构 |
数据库支持 | MySQL、PgSQL | 任意数据库 | 任意数据库 |
配置管理 | 去中心化 | 中心化 | 中心化 |
部署方式 | 依赖工程 | 中间件 | 中间件 |
业务侵入性 | 较低 | 无 | 无 |
连接开销 | 高 | 低 | 低 |
事务支持 | XA、Base、Local事务 | 同前者 | XA事务 |
功能丰富度 | 多 | 多 | 一般 |
社区活跃性 | 活跃 | 活跃 | 一言难尽 |
版本迭代性 | 高 | 高 | 极低 |
多路由键支持 | 2 | 2 | 1 |
集群部署 | 支持 | 支持 | 支持 |
分布式序列 | 雪花算法 | 雪花算法 | 自增序列 |
MySQL
!MySQL
源码没有?MySQL
源码还不熟悉,所以给你开三千五,干不干!..............
,干!您看人可真准~,嘿嘿结语
疫情当下,这让原本很多一年一跳一涨薪的开发者,从此进入了互联网寒冬,企业缩招、停招、裁员等情况屡见不鲜,虽然相较于其他传统行业而言,IT
开发行业受影响范围小很多,但依旧造成了一系列的连锁反应,随着应届毕业生越来越多,这也让诸多岗位的要求越来越高,但薪资反而越来越低。
同时,无论是工作一段时间、或工作多年的程序员,亦或是刚从校园毕业的应届生,为了能够更好的找到符合意愿的工作,近两年的内卷更为严重,离职待业的开发者在家学技术,在职工作的程序员为了应对随时可能发生的“优化”,也仍然在学习的路上不断前行,也包括了一些毕业后没有找到理想工作的应届生,几乎各自身上都有着学习的影子。
但许许多多在学习路途上“埋头苦干”的小伙伴,基本上都只是为了应付面试而在学习,诸多时候为了使自己面试造火箭的能力更上一层楼,而这章关于MySQL
面试的文章,也真心希望能够帮助到每一位准备或正在面试的后端小伙伴,助力于每一位求职者拿到心满意足的Offer
,我与诸君共勉之!