目录
一、如何定位慢查询
1、慢查询原因:
2、如何定位慢查询
3、面试官:MySQL中,如何定位慢查?
二、sql语句执行很慢如何分析/优化
1、通过explain字段+查询语句查看索引使用情况
2、面试官:SQL语句执行很慢,如何分析?
三、索引概念以及底层数据结构
1、什么是索引
2、索引的底层数据结构是什么?
3、为什么选择B+树?
4、面试官:了解过索引吗? (什么是索引)
5、面试官:索引的底层数据结构了解过嘛 ?
6、面试官:B树和B+树的区别是什么呢?
四、聚簇索引、非聚簇索引、回表查询
1、什么是聚簇索引(聚集索引),什么是非聚簇索引(二级索引),什么是回表查询?
2、面试官:什么是聚簇索引什么是非聚簇索引?
3、面试官:知道什么是回表查询嘛 ?
五、覆盖索引,超大索引优化
1、什么是覆盖索引?
2、 超大分页查询
3、面试官:知道什么叫覆盖索引嘛 ?
4、面试官: MYSQL超大分页怎么处理?
六、索引创建原则
1、原则
2、概括:
3、面试官:索引创建原则有哪些?
七、什么情况下索引会失效
1、什么情况下索引会失效
2、概括
3、面试官:什么情况下索引会失效 ?
八、谈谈你对索引优化的经验
1、表的设计优化
2、SQL语句优化
3、主从复制、读写分离
4、概括
5、面试官: sql的优化的经验
6、面试官:创建表的时候,你们是如何优化的呢?
7、那在使用索引的时候,是如何优化呢?
8、面试官:你平时对sql语句做了哪些优化呢?
九、事物的特性
1、事务概念
2、事务的特性(ACID)
3、面试官:事务的特性是什么? 可以详细说一下吗?
十、并发事务问题、隔离问题
1、并发事务问题
2、隔离级别
编辑 3、面试官:并发事务带来哪些问题?
4、面试官: 怎么解决这些问题呢? MySQL的默认隔离级别是?
十一、undo log 和redo log的区别
1、先引入缓冲池和数据页的概念
2、redo log
3、undo log
4、undo log和redo log的区别
5、面试官: undo log和redo log的区别
十二、解释下MVVC
1、事务中的隔离性是如何保证的呢?
2、解释下什么是MVVC?
3、隐藏字段
4、undo log
5、readview
6、事务中的隔离性是如何保证的呢?(你解释一下MVCC)
7、 面试官:事务中的隔离性是如何保证的呢?(你解释一下MVCC)
十三、主从同步原理
1、主从同步原理
2、概括
3、 面试官:说一下主从同步的原理?
4、排疑:mysql主从复制的时候为什么不直接将bin log直接读取并执行到从库,而是先保存到relay log再保存到从库?
十四、分库分表
1、拆分策略
2、分库分表产生的问题
3、概括
十五、说一说MyISAM索引的实现原理
十六、innodb为什么要用自增id作为主键?
十七、MySQL常见的存储引擎InnoDB、MyISAM的区别?
1、事务
2、锁级别
3、行数
4、索引
十八、数据库三范式,根据某个场景设计数据表?优缺点是什么?
1、第一范式(确保每列保持原子性)
2、第二范式(确保表中的每列都和主键相关)
3、第三范式(确保每列都和主键列直接相关,而不是间接相关)
十九、数据库悲观锁和乐观锁的原理和应用场景?
1、悲观锁
2、乐观锁
二十、Myql中的事务回滚机制,持久性,隔离级别的实现
1、事务回滚机制
2、持久性
3、隔离级别
二十一、说一说drop、delete与truncate的区别?
1、drop
2、truncate
3、delete
二十二、索引是什么?
二十三、索引的优缺点?
1、优点
2、缺点
二十四、MySQL 索引类型都有什么?
1、按存储结构来划分
2、从应用层次来划分
3、从数据的存储方式划分,根据数据的物理顺序与键值的逻辑关系
二十五、索引的底层实现?
1、Hash 索引
2、B-Tree 索引
3、B+Tree 索引
4、B+Tree 性质:
二十六、为什么索引结构默认使用 B+Tree?
1、B+Tree:
2、Hash
3、二叉树
4、红黑树
表现:页面加载慢、接口无响应,或者响应时间过长(超过1s)
如果,项目中没有这种运维的监控系统,其实在MySQL中也提供了慢日志查询的功能,可以在MySQL的系统配置文件中开启这个慢日志的功能,并且也可以设置SQL执行超过多少时间来记录到一个日志文件中,我记得上一个项目配置的是2秒,只要SOL执行的时间超过了2秒就会记录到日志文件中,我们就可以在日志文件找到执行比较慢的SQL了。
比如explain select * from user
MySQL的InnoDB引擎采用的B+树的数据结构来存储索引
首先看二叉搜索树最好的情况性能是O(logn),最坏情况是O(n)
然后来看红黑树,它的时间复杂度是O(logn),但是在数据量特别大的时候,树会特别高,就会遍历很多层级,对性能影响较大
下来是B-Tree,B树是一种多叉路衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉以一颗最大度数(max-degree)为5(5阶)的b-tree为例,那这个B树每个节点最多存储4个key。并且每个节点下面存储的是数据。比如20节点下方存储的是它的数据。
最后是B+树 ,B+Tree是在BTree基础上的一种优化,使其更话合实现外存储索引结构,InnoDB存储引警就是用B+Tree实现其索引结构。
与B树的区别就是非叶子节点只存储指针,不存储数据。只在叶子节点存储数据,非叶子节点作用只是导航找到叶子节点获取数据
B树与B+树对比:
聚集索引选取规则:
索引效果展示:
覆盖索引是指查询使用了索引,返回的列,必须在索引中全部能够找到
在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。
我们一起来看看执行limit分页查询耗时对比:
因为,当在进行分页查询时,如果执行 limit 9000000,10,此时需要MySQL排序前9000010 记录,仅仅返回9000000-9000010的记录,其他记录丢弃,查询排序的代价非常大。
优化思路:优化思路: 一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。
优化前速度是11s多,这是优化后的效果
①违反最左前级法则
② 范围查询右边的列,不能使用索引
③不要在索引列上进行运算操作,索引将失效
④字符串不加单引号,造成索引失效
⑤类型转换会造成索引失效
⑥以%开头的Like模糊查询,索引失效。如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效
不可重复读和脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据,但是其违反了事务一致性的要求。
不可重复读和幻读区别:不可重复读主要是针对数据的更新(即事务的两次读取结果值不一样),而幻读主要是针对数据的增加或减少(即事务的两次读取结果返回的数量不一样)。
回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚和 MVVC(多版本并发控制)。undo log和redo og记录物理日志不一样,它是逻辑日志。
undo log可以实现事务的一致性和原子性
全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突MVCC的具体实现,主要依赖于数据库记录中的隐式字段、undo log日志、readView(读视图)。
4.1、undo log的版本链
这是四个事务,对应着四次不同的修改
此时对应表中的数据如下,其中DB_TRX_ID为事务id,默认为1,DB_ROLL_PTR为回滚指针,目前未指向其他地址。当发生写操作就会在undo log生成记录,记录修改之前的数据,并把DB_ROLL_PTR指针指向修改前记录的地址,且事务ID自增1。
①此时经历事务2的操作,将id为30的age修改为3.那么在记录中的age改为3,DB_TRX_ID自增1为2,并且DB_ROLL_PTR改为上个版本的地址
②事务3修改了id为30的name为A3,则记录中的name改为A3,并且DB_TRX_ID自增1为3,DB_ROLL_PTR修改回滚指针地址为上个事务id为2的地址。并且把事务id为2的回滚指针地址指向事务id为1的地址。
③事务4修改了id为30的age为10,则记录中的age为10,DB_TRX_ID自增1为4,DB_ROLL_PTR指向事务id为3记录的地址。并把事务ID为3的回滚指针指向事务ID为2的记录的地址。
④不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
ReadView(读视图)是快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(末提交的) id。
5.1、当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select... lock in share mode(共享锁),select ...for update、 update、 insert、 delete(排他锁)都是一种当前读。
5.2、快照读
简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
5.3、ReadView包含的4个核心字段
5.4、版本控制链访问规则
其中trx_id代表当前事务ID,也可能是历史事务ID
不同的隔离级别,生成ReadView的时机不同:
5.5 、在READ COMMITTED(读已提交)的隔离级别下,事务中每一次执行快照读时生成ReadView
5.5.1、对于第一个读视图根据以下规则可以进行判断
事务ID当前为4
事务ID当前为3
事务ID当前为2
因此当前读视图可以访问的版本链是事务ID为2的记录
5.5.2、对于第二个读视图
事务ID当前为4
事务ID当前为3
因此当前读视图可以访问的版本链是事务ID为3的记录
5.6、在REPEATABLE READ(可重复读)的隔离级别下,事务中每一次执行快照读时生成ReadView
RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
操作与读已提交相同
MySQL中的多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突
①隐藏字段:
② undo log:
③readView解决的是一个事务查询选择版本的问题
一个java应用首先要去连接数据库的中间件,中间件至少连接两个库一个是主库,一个是从库。主库负责写数据,从库负责读数据。当主库写数据的时候,就把数据同步到从库中。所以主要解决的是如何同步的,同步的原理。
二进志(BINLOG)记录了所有的 DDL(数据定义语言)语和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。
复制分成三步:
主从同步原理
MySQL主从复制的核心就是二进制日志binlog(DDL(数据定语言)语和 DML(数据操纵语言)语句)
MySOL主从复制的核心就是二进制日志,二进制日志记录了所有的 DDL语句和 DML语句
具体的主从同步过程大概的流程是这样的:
分库分表的时机:
1.1、垂直分库
一个数据库有多个表,且都为热点数据表,为了避免单个数据库访问压力过大,将表分开存储到不同的数据库中。
垂直分库:以表为依据,根据业务将不同表拆分到不同库中
特点:
1.2、垂直分表
一个表中有多个字段,该表的某些字段访问压力过大但某些字段访问压力小,可以将表的字段根据访问量拆分不同的表保存到数据库中。
垂直分表:以字段为依据,根据字段属性将不同字段拆分到不同表中 。
特点:
拆分规则:
1.3、水平分库
某些数据库的总体访问压力过大,为了解决这种情况,可以将数据拆分到不同的数据库中,但是会造成不同数据库的数据是不同的,解决方法是使用路由规则来解决。
水平分库: 将一个库的数据拆分到多个库中。
但是每个库的数据不一定都相同,为了解决这种问题,可以根据以下规则来解决
路由规则:
特点:
1.4、水平分表
某些表的总体访问压力过大,为了解决这种情况,可以将表中的数据拆分到多个表中,但是会造成多个表的数据是分散的,解决方法是使用路由规则来解决。
水平分表:将一个表的数据拆分到多个表中(可以在同一个库内)
特点:
分库之后产生的问题:
使用中间件即可解决以上问题
业务介绍
具体拆分策略
MyISAM索引实现
MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,MyISAM索引的原理图如下。
这里假设表一共有三列,假设我们以Col1为主键,则上图是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。
如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示。同样也是一颗B+Tree,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置。
如果使用随机数字作为索引,比如身份证号等数字,那么对于添加一条数据,就会可能出现重构索引,会造成频繁的移动,对性能造成了巨大的损耗。
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说 在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。
优点:可以尽量得减少数据冗余 缺点:对于查询需要多个表进行关联,更难进行索引优化 反范式化: 优点:可以减少表得关联 缺点:数据冗余以及数据异常。
悲观锁,先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。
当数据库执行select … for update时会获取被select中的数据行的行锁,select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
乐观锁则与悲观锁相反,先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。Java 并发包中的 AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。
undo log实现事务的回滚机制,所有事务进行的修改都会先记录到这个回滚日志中,然后在对数据库中的对应行进行写入。当事务已经被提交之后,就无法再次回滚了回滚日志作用:
redo log 是实现事务的持久性。当数据修改时候,就会将已修改的数据写入缓冲池的redo log,不管是否提交。只要缓冲池的redo log出现变化的时候,磁盘中的redo log就会将缓冲池的redo log同步到磁盘中的redo log中。当出现宕机的时候,数据库就会从磁盘中的redo log进行事务回滚,保证事务的持久化。
MVVC+锁实现数据库的隔离级别对在同一时间执行的事务进行控制,限制不同的事务对于同一资源的访问和更新,锁分为共享锁和互斥锁
Drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令也不能回滚。
Truncate删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,TRUNCATE比delete更快,占用的空间更小。
Delete用来删除表的全部或者一部分数据行,执行delete之后,用户需要提交(commmit)或者回滚(rollback)来执行删除或者撤销删除。会触发这个表上所有的delete触发器
在 MySQL 中,索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录,索引中包含着对数据库所有记录的引用指针。
通过使用索引可以大大加快数据的查询速度(使用索引最主要的原因)
基于哈希表实现,只有精确匹配索引的所有列查询才有效。对于每行数据,存储引擎都会对其计算一个哈希码(hash code),并且 Hash 索引将所有的哈希码存储在索引中,同时在索引表中保持指向每个数据行的指针。
B-Tree 结构里每个节点包含了索引值和表记录的信息,数据分布在各个节点之中,可以加快访问速度,不需要扫描全表获取数据。
B-Tree 的改进,是 MySQL 使用的索引存储结构。数据都存储在叶子节点上,在叶子节点间增加了顺序访问指针,相较于 B-Tree 每次都需要从根节点开始查找,B+Tree 存储的结构范围查找效率更高
树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高
树的高度随着数据量增加而增加,IO代价高
查询语句的执行流程如下:
更新语句执行流程如下: