MySQL常见6个考题在实际工做中的运用

题目一java

MyISAM和InnoDB的区别,何时选择MyISAMgit

参考回答redis

InnoDB是目前MySQL主流版本(5.六、5.七、8.0)默认的存储引擎,支持事务、外键、行级锁,对于并发条件下要求数据的一致性,适用于对数据准确性要求高的场景。spring

MyISAM只支持表级锁、数据排列是按照插入顺序,没有作规则排序。适合应用以查询和插入为主,只有不多量的更新和删除操做,对事务的完整性和并发性要求不是很高的场景。sql

实际运用数据库

看到不少人在选择存储引擎的时候会无脑的选择InnoDB,这个选择合理的一点是若是对数据准确性要求没有那么高,直接用NoSQL就行了。用MySQL就是为了可靠啊。json

可是实际工做中,我设计的数据库中一般都会有几张MyISAM的数据表,一般用来存储历史记录,与使用InnoDB存储实时记录信息的配合使用。缓存

举个例子:好比一条物流信息,在实时的表里存着目前物流的状态:好比配送中。这条物流在历史上通过了:正在通知快递公司取件、XXX已收揽等,这张记录表基本只有插入和查询,而且丢失一个中间状态不影响当前结果,这就很合适用MyISAM。mybatis

 

题目二并发

简述MySQL的MVCC多版本并发控制

参考回答

MVCC是对于事务隔离级别的读已提交RC和可重复读RR,基于乐观锁的实现。在LBCC(基于锁的并发控制)RC、RR和串行化分别是经过加行锁、间隙锁和表锁来基于悲观锁实现。而乐观锁的原理就是在特定的时间点(RC是每次读时,RR是事务开始时)生成一个当前快照,读数据读取快照,只在提交时判断是否有冲突,相似于git的branch和commit。

MVCC会在新开启一个事务时,给事务里包含的每行记录添加一个当前事务ID和回滚指针。并包含一个Read View,Read View里保存了当前活跃的事务列表,小于这些列表的最近的事务ID才是可见的。这样保证了读到的都是已提交的事务。

实际运用

MVCC不只能够用于数据库,也是很常见的一种并发控制手段。好比使用有限状态自动机来控制的订单状态,在更新订单状态的时候先查询当前状态,好比当前状态是订单未提交,则更新时update XXX set status='订单已提交' where status='订单未提交',若是执行这条语句时,status已经发生了改变,这条语句就执行失败了。这样不经过数据库自身事务的MVCC,在业务逻辑里也实现了MVCC思想的乐观锁设计。

 

题目三

分布式锁的实现方式

参考回答

主流有三种

1>基于数据库

1.1>基于数据库主键:插入一条数据,指定主键。若是有两条插入会主键冲突,并发执行失败

1.2>基于数据库排他锁:提交一个update事务,若是这个事务不提交,其余也对锁定范围内执行update就会阻塞,解决并发问题

2>基于缓存好比redis的setNX

3>基于zookeeper

实际运用

相信不少人选择分布式锁都是选择第二种,第三种虽然并发性差一下,若是原本就引入了zk,而没有缓存,而分布式锁应用量又不那么大,为了减小引入新组件带来的风险和维护成本,也有可能选择zk。不少人大概认为本身没有用过基于数据库的分布式锁,实际上在不使用MVCC的时代并非这样。

在使用spring进行业务开发的时候,常见的一种场景就是使用spring配置事务。默认级别是Repeatable Read可重复读。在这里面若是使用的是LBCC,一进入事务就加入一个排他锁,好比insert、update、delete或者select XXX for update。而后作其余的,好比进行一个RPC调用。这时候一旦出现并发,只有一个能顺利执行,其余都会被阻塞。实际上就至关于使用了分布式锁。

 

题目四

为何采用B+树做为索引结构?

参考回答

若是采用Hash表,范围查找须要全表扫描;若是采用二叉查找树,因为没法保证平衡,可能退化为链表;若是采用平衡二叉树,经过旋转解决了平衡的问题,可是旋转操做效率过低;若是采用红黑树,树过高,IO次数多;若是采用普通B树,节点要存数索引和数据,一个内存页可存储的数据仍是少,另外范围查找也须要屡次IO;

而B+Tree有三个特性:

1>非叶子节点不存储data,只存储索引(冗余),能够放更多的索引

2>叶子节点包含全部索引字段

3>叶子节点用指针连接,提升范围查询的性能

实际运用

在分布式场景下,咱们的业务ID都是全局惟一的字符串。若是单纯从业务上来考虑,用业务ID做为数据库的主键就足够了。能够DBA每每要求使用整型的自增主键做为数据库主键,而这个主键对业务来讲就是个浪费,没有任何业务含义。

若是了解了索引的底层结构就不难理解

1>整型比字符串占用更少的空间

2>同时大小比较也很快

3>之因此要自增是每次插入新的记录,对于叶子节点来讲:记录会顺序的添加到当前索引节点的后续位置,当一页写满,会自动开辟一个新的页。而若是使用非自增主键,就须要插入的时候移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要读回来。分页操做形成大量的碎片,必须经过优化操做重建表并优化填充页面。

 

题目五

什么叫作覆盖索引?

参考回答

只须要在一棵辅助索引树上就能够获取SQL所须要的全部列数据,不须要回表。

实际运用

一些持久层框架好比mybatis的generator插件能够自动生成sql配置文件,这些配置文件每每效率很低。可是刚毕业的同窗不少都不会去改这个文件,好比只须要个别列的时候会用java的lambda表达式等方式从逻辑上作处理。结果形成一些性能的问题。

我在根据一些条件进行范围查找的时候,若是只须要返回ID或者个别列,会本身去改mybatis的generator自动生成的文件,缘由是尽可能使用覆盖索引,较回表速度快。

想验证是否使用了覆盖索引,能够用explain执行计划,查看extra字段,若是只显示Using index说明正确使用了覆盖索引。若是extra为空或者除了using index还有filesort说明触发了回表。

 

题目六

查询在何时不走索引

参考回答

主要三种状况

1>不知足走索引的条件,常见的状况有

1.1>不知足最左匹配原则

1.2>查询条件使用了函数

1.3>or操做有一个字段没有索引

1.4>使用like条件以%开头

2>走索引效率低于全表扫描,常见的状况有

2.1>查询条件对null作判断,而null的值不少

2.2>一个字段区分度很小,好比性别、状态

3>须要回表的查询结果集过大,超过了配置的范围

实际运用

使用索引是为了对查询作优化,要衡量优化效果须要数听说话。因此须要一些工具来衡量,经常使用的有:

1>慢查询日志

开启慢查询日志,能够针对慢SQL进行分析看看哪些能够用索引进行优化

2>show processlist

show processlist 语句能够查看当前正在执行的SQL,若是一些SQL执行慢,block了其余的SQL,这是个很好的工具

3>show profile分析SQL

使用这个工具能够分析出时间究竟耗费在哪一个阶段。先查询是否支持

支持的话,能够用select @@profiling 查看是否开启,若是结果为0说明未开启。须要先set @@profiling=1;

这时候就能够用show profiles查看每一条SQL语句耗费的时间

 

 

show profile for query XXID 能够查看具体耗费在哪一个阶段

4>Trace分析优化器的执行计划

使用set optimizer_trace='enabled=on',end_markers_in_json=on;能够打开trace分析,想查看具体的优化器执行计划,只要执行

select * from `information_schema`.optimizer_trace便可

 

 

点击开每一步都有很详细的分析

 

总结

知识只要学透了均可以灵活运用。在运用的时候要注意衡量效果。一个常见的误区是开发人员无脑的在MySQL上层加缓存,用来提升效率。可是缓存只适用于读多写少的状况,好比在金融交易系统,数据读写比例1:1。数据老是查询出来下一刻就被更新了,这时候用缓存反而加剧系统的负担和复杂性。

这时候,咱们能够先利用工具查询数据库的读写比例。好比show global status like 'Com_______' 这个SQL能够查看select、update、insert、delete都被执行了多少次。

或者show global status like 'Innodb_row_%' 除了查看Innodb的读写状况,还能够查看锁的状况。

 

思考

请网上搜索一下「58Mysql军规」而后思考每条军规背后的理论支撑。

相关文章
相关标签/搜索