mysql数据库是一种关系型数据库。基于关系模型将数据以二维表的形式存储为一张张有关联的表。
Mysql整体架构
Mysql采用插件式存储引擎架构,使其能够将查询处理与其他任务分离开来,如连接、数据存储等。这种架构让mysql能够在不同的业务场景下选择合适的存储引擎提高数据库查询效率。
mysql架构图
- 连接层
-
- 负责连接处理、安全协议、授权认证等功能
- 该层引入了线程池的概念,为通过了安全认证的客户端提供线程服务
- 该层允许使用ssl协议进行连接
- 服务层
-
- 完成查询的解析、分析、优化、缓存以及提供所有的内置函数
- 所有跨存储引擎的操作均在此层实现
- 引擎层
-
- 存储引擎真正负责了mysql中数据的存储与提取,服务器通过API的方式与存储引擎通信
- 存储层
-
- 将mysql的数据存储在文件系统中
问题1:画出mysql的架构图
- 客户端向连接器发起请求:身份验证、授权
- 检查查询是否存在缓存,如果存在直接返回
- 分析器对sql进行词法和语法分析
- 优化器对sql进行执行优化提高查询效率
- 执行器检查用户是否有执行权限,有的话就调用API访问存储引擎
Mysql存储引擎
存储引擎是什么?
是mysql中的组件,该组件真正实现了数据的存储和索引技术,不同的存储引擎提供了不同的存储结构、不同的索引技巧、不同的锁定水平。mysql存储引擎可以灵活使用,同一个数据库可以使用不同的存储引擎,以满足各种场景需求下的性能需求。
常见的存储引擎
常见的存储引擎就 InnoDB、MyISAM、Memory、NDB。
InnoDB 现在是 MySQL 默认的存储引擎,支持事务、行级锁定和外键
不同存储引擎存储结构对比
mysql中.frm文件存储着数据表的元数据,如数据的表结构等信息;这与存储引擎无关,不同的存储引擎,只要有数据表就一定会有.frm文件
MyISAM物理文件结构
- .frm
- .MYD(MYDate):存储MyISAM存储引擎的数据信息
- .MYI(MYIndex):存储MyISAM存储引擎的索引信息
InnoDB物理文件结构
- .frm
- .ibd:(独享表空间模式)存储InnoDB存储引擎的数据信息
- .ibdata:(共享表空间模式)存储InnoDB存储引擎的数据信息
独享表空间意为每一张表就有它独享的表空间,一张表就有一个ibd文件;共享模式则将所有的表数据都存储在ibdata文件中
MyISAM与InnoDB的区别
- InnoDB支持事务,MyISAM不支持
- InnoDB最小的锁颗粒度为行锁,而MyISAM最小颗粒为表锁,在高并发情况下效率低下
- InnoDB位为聚族索引,而MyISAM位非聚族索引,InnoDB必须含有主键,如果没有设置会找到第一个唯一索引作为主键如果都没有那么就会默认生成,聚族索引叶子结点直接存放了数据信息,因此使用主键索引在InnoDB中进行查询效率特别高,若使用其他辅助索引则需要进行二次查询,因为其他索引的叶子节点存储的是主键信息
- InnoDB支持外键
- InnoDB不保存具体的行数,因为支持事务所以在多线程情况下无法保证数据的一致性。
Mysql存储引擎面试题
问题3:一张表,里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把Mysql重启,再insert一条记录,这条记录的ID是18还是15 ?
MyISAM存储引擎中该记录ID为18,InnoDB存储引擎中该记录ID为15,因为InnoDB自增主键最大ID值是存储在内存中。
问题4:哪个存储引擎执行 select count(*) 更快,为什么?
MyISAM,因为它会将总行数记录在磁盘中,InnoDB统计行数需要将所有记录读出来一条一条算总数。因为InnoDB的事务特性导致在并发情况下无法确定总行数,因此需要每次都重新统计
Mysql的数据类型
五大类型
- 整形类型
- 浮点类型
- 字符串类型
- 日期类型
- 其他类型
Mysql索引
是什么?
官方定义:索引是帮助Mysql高效获取数据的数据结构;
即可知索引的本质是一种数据结构,可通俗的理解索引为一颗排好序的快速查找的数据结构
作用:提高mysql的查询效率,可以类比书的目录、字典等
优势
- 提高IO效率:在一次查询中尽可能减少发生IO的次数提高查询效率。
- 提高排序效率:mysql索引采用的是B+Tree的数据结构会对索引列进行排序。
劣势
- 需要占用额外的内存空间。
- 使用索引会降低插入和更新效率,因为更新数据的同时也需要更新索引表
Mysql的索引分类
数据结构角度
- B+树
- 哈希索引
- 全文索引
- R-Tree索引
物理存储角度
- 聚族索引
- 非聚族索引
两种索引都是采用的B+树数据结构
逻辑角度
- 主键索引
- 普通索引/单列索引,只包含一个字段的索引
- 复合索引/多列索引,包含多个字段的索引,使用符合索引时遵循最左前缀原则
- 唯一索引
- 空间索引
Mysql索引结构
Mysql索引实现在存储引擎层面,即使用同一种索引,在不同存储引擎中其实现和行为都可能有所差异。
在Mysql中InnoDB和MyIsam存储引擎都是用B+树索引。B+树结构与B树相似,区别只在于B+树将所有的数据值都存放在叶子节点上,且将所有的叶子结点用指针连接成了一条数据链。
系统磁盘与数据库最小处理单位
磁盘块,是磁盘处理信息的最小读取单位,mysql数据库处理数据的最小单位是页,可以设置大小,一般默认16k比磁盘块要大,因此mysql在保存数据时会申请连续的磁盘块作为一页来进行处理
BTree
BTree是一种为提高磁盘等外部设备查询效率而设计的平衡查找树。
BTree优势
B树中每一个节点都携带着定位目标数据的定位信息,使其能够在发生更少磁盘IO的情况下找到目标数据。
描述Btree首先需要定义一条记录为一个二元组【K,V】K为键值,V为除键值外的数据,每一个记录的键值唯一
m阶BTree特性
一颗m阶B树具有如下的特性
- 所有结点:每个结点至多有m个孩子
- 根结点:若跟结点不为叶子结点则根结点至少有2个孩子
- 叶子结点:所有叶子结点均在同一层,且只有数据信息
- 非根非叶子结点:至少有m/2个孩子
结点内容:
- 每个结点含有n个关键字((P0,P1,......Pn),(K1,K2,......,Kn))
- m/2 - 1<=n <= m - 1
- K为关键字,且按照升序顺序排序
- P指向孩子结点的根节点,Pi指向的孩子值均大于Ki且均小于K+1
BTree是如何提高查询效率的?
数据库数据都是持久化在外部存储设备的,而外部设备的查询速度和内存的查询速度相差一个数量级,因此要提高查询效率重点在于减少与外部存储设备发生IO的次数。B树按照键值将数据进行排序形成一颗平衡查找树,每次查从根节点开始比较键值大小直至找到目标数据,相较于全局搜索要快得多。
B+Tree索引
MyISAM和InnoDB存储引擎都是用了B+树作为索引结构,所有的数据都存储在叶子上,并且所有叶子结点都是用指针相连,以加快相邻数据的查询速度
B+树的优势
B树的除叶子节点外其他结点都包含了数据,而一个结点(一页)的大小是有限的,因此包含的键值就少了进而导致B树的深度会与磁盘发生更多的IO次数。因此B+树优化了这一点,规定所有非叶子节点只保存键值,大大增加了每个结点保存的键值数减少树的高度。
B+Tree和BTree的区别
- 数据都存储在叶子结点中
- 叶子结点都用指针连接形成链表环
- 非叶子节点只保存键值
B+树复合索引的情况
按照顺序依次排序作为键值建立索引。如将A、B、C字段作为复合索引,则mysql会首先排序A值当遇到A值相同时再比较B值一次类推建立索引,因此在进行查询的时候要使用符合索引必须遵守最左匹配特性,按照上面的例子如果查询条件只有B,那么建立的B+树无法进行查询,因为键值中的B列并不是有序的,是要在保证A值匹配的原则下进行查询才是正确的。
MyIsam存储引擎的索引结构
使用的是B+树结构,其索引中存储的数据并不是实际的数据值而是实际数据的物理地址的偏移量。这样的索引被称为非聚簇索引。MyIsam的主键索引与非主键索引区别不大,主要的区别就是主键索引不能重复。
具体的读取流程
- 从索引文件.myi中找到索引结点
- 读取结点中的文件指针
- 从数据文件中使用文件指针找到具体的数据
InnoDB存储引擎的索引结构
使用B+树结构,其主键索引数据保存了实际数据这样的索引称为聚簇索引,非主键索引数据保存着主键,需要通过主键索引在找到具体的数据(该过程称为回表)。
Mysql索引相关面试题
说说你对 MySQL 索引的理解?
数据库索引的原理,为什么要用 B+树,为什么不用二叉树?
聚集索引与非聚集索引的区别?
InnoDB引擎中的索引策略,了解过吗?
创建索引的方式有哪些?
聚簇索引/非聚簇索引,mysql索引底层实现,为什么不用B-tree,为什么不用hash,叶子结点存放的是数据还是指向数据的内存地址,使用索引需要注意的几个地方?
为什么MySQL 索引中用B+tree,不用B-tree 或者其他树,为什么不用 Hash 索引
聚簇索引/非聚簇索引,MySQL 索引底层实现,叶子结点存放的是数据还是指向数据的内存地址,使用索引需要注意的几个地方?
使用索引查询一定能提高查询的性能吗?为什么?
InnoDB存储引擎为什么推荐使用整型自增主键而不是选择UUID?
InnoDB引擎为什么非主键索引结构叶子节点存储的是主键值?
为什么Mysql索引要用B+树不是B树?
面试官:为何不采用Hash方式?
Hash索引
使用哈希算法将数据库数据关键字转为定长的哈希值,与这条数据的行指针一同存入哈希表中。mysql中只有Memory和NDB存储引擎支持
哪些情况需要创建索引
- 频繁作为查询条件的列
- 与其他表关联的列
- 用于排序的字段
- 统计和分组的字段
哪些情况不需要建立索引
- 表数据量少
- 经常增删的表
- 频繁更新的字段
索引覆盖
也就是不需要回表的查询,原理就是要查询列的值已经全部包含在索引中,就不再需要去查询键值对应的文件数据了。可以使用explain查看是否有用到索引覆盖
Mysql特殊查询情况
count(*) 和 count(1)和count(列名)区别 ps:这道题说法有点多
执行效果上:
count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
count(1)包括了所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。
执行效率上:
列名为主键,count(列名)会比count(1)快
列名不为主键,count(1)会比count(列名)快
如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)
如果有主键,则 select count(主键)的执行效率是最优的
如果表只有一个字段,则 select count(*) 最优。
MySQL中 in和 exists 的区别?
exists固定会对外表进行全表扫描,查询exists中返回的结果是否为真,为真则当前记录符合条件。
因此如果子表大时使用exists,子表小使用in
UNION和UNION ALL的区别?
UNION和UNION ALL都是将两个结果集合并为一个,两个要联合的SQL语句 字段个数必须一样,而且字段类型要“相容”(一致);
- UNION在进行表连接后会筛选掉重复的数据记录(效率较低),而UNION ALL则不会去掉重复的数据记录;
- UNION会按照字段的顺序进行排序,而UNION ALL只是简单的将两个结果合并就返回;
SQL的执行顺序
手写
SELECT DISTINCT <select_list>
FROM <left_table> <join_type>
JOIN <right_table> ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>
复制代码
机读
FROM <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>
总结
mysql 的内连接、左连接、右连接有什么区别?什么是内连接、外连接、交叉连接、笛卡尔积呢?
Mysql的事务
mysql事务是由一组sql组成的逻辑处理单元
事务的基本要素(ACID)
- 原子性:事务中的操作要么一起执行,要么一起不执行;在执行过程中报错就会进行回滚
- 一致性:事务必须保持系统的状态不管在任何状态下都要保持一致。比如一个账户的金额进行取200,账户的总金额就应该只减少200而不是减少其他金额数
- 隔离性:各个事务之间的执行互不影响
- 持久性:事务执行完毕后对数据影响是持久的,不会被回滚
并发事务带来的问题
- 更新丢失(LostUpdate):由于多个事务在某时间段内对同一行记录进行更新操作因为更新都是基于最初取到的值致使某些事务操作的结果被覆盖
- 脏读(DirtyReads):某事务读取到的值是另一事物执行的中间值,但该事物最终回滚了
- 不可重复读(Non-RepeatableReads):某事务多次读取同一个参数得到的值却不同,因为事务执行期间有别的事务对该值进行了修改
- 幻读(PhantomReads):某事务多次读取某表数据的总行数不同,因为事务执行期间有别的事务对该表进行了增删操作
不可重复读与幻读的区别
不可重复读是同一事务内多次读取某个参数的值不同,而幻读是多次读取表的总数量不同。一个是被其他事物修改了读取的数据,另一个是被其他事物对表进行了增删操作
解决并发事务引起的问题
- 解决“更新丢失”:要防止更新丢失的问题出现因需要结合实际业务逻辑这就需要应用系统的配合控制。单纯的靠数据库无法解决。
- 解决脏读、不可重复读、幻读:使用数据库提供的事务隔离级别来解决
-
- 加锁的方式来解决
- 使用MVCC来来解决
事务的隔离级别
- 读未提交(READ-UNCOMMITED):允许读取未提交事务修改的数据最低的隔离级别,存在脏读、不可重复度、幻读
- 读已提交(READ-COMMITED):允许读取已经提交事务的数据,可防止脏读的出现
- 可重复读(REPEATABLEREAD):事务读取某行时不允许塔事务对当前行进行修改,防止不可重复无问题出现
- 序列化(SERIALIZABLE):最高级别的事务隔离级别,串行化处理事务
Mysql的默认事务隔离级别是可重复读,且隔离效果达到了序列化的级别并且对并发性能的影响不大
MVCC多版本并发控制器
MVCC可理解为行锁的变种,因避免了很多情况下的加锁操作,所以它的开销相比一般的行锁更小。MVCC的实现有很多种但大多都实现了非阻塞的读操作,写操作只锁必要的行。
MVCC实现原理
保存数据在某个时间点的快照,以此来达到每个事物来读取到的数据都相同的效果
MVCC工作流程
MVCC会在每个数据中额外记录两个版本号,一个是行记录创建时的版本号、另一个是行被删除时的版本号
- SELECT:
-
- InnoDB存储引擎查找创建版本号比当前系统版本早的记录确保查找到的数据都是在当前事务开始就存在的
- InnoDB存储引擎查找删除版本号比当前系统版本早的或者删除版本号没有定义的记录,确保却找到的数据在事物开始前没有被删除
- INSERT:
-
- 为数据记录行创建版本号
- DELETE:
-
- 为数据记录删除版本号
- UPDATE:
-
- 更新数据的创建版本号和删除版本号
MVCC优劣势
- 优势
-
- 使用MVCC能够避免大多需要加锁的情况提高查询效率
- 劣势
-
- 需要额外的存储空间
- 操作数据时是要额外的检查工作
MVCC只在读已提交和可重复读两种隔离级别下进行工作
事务日志
什么是事务日志?
将事务将要做的操作以日志的形式记录下来持久化在磁盘中
为什么需要事务日志?
- 提高事务执行的效率
-
- Innodb使用事务日志来减少提交事务时的性能开销。因为事务执行日志已经持久化在磁盘,因此在事务提交时不需要将所有的数据修改从缓存中写入到磁盘中。
- 事务执行的过程中对数据或者索引的修改通常会映射到多个表空间,持久化这些修改需要发生多次随机IO,所以使用事务日志将随机IO改为顺序IO能够有效提高处理效率。
- Innodb使用一个后台线程智能的将缓存中修改的数据批量的写入磁盘中,使得写入数据的效率更高。
- 保证事务的基本要素
-
- 原子性
- 一致性
- 持久性
大部分的存储引擎都是这样实现的,称为预写式日志,修改数据需要写两次磁盘
Mysql的事务日志
重做日志
记录了事务操作步骤,当事务执行中途发生意外时可以恢复执行状态继续执行事务
回滚日志
记录了数据修改前的状态,当事务执行异常时可以将数据回滚至原来的状态
事务的实现
基于存储引擎实现,mysql支持事务的存储引擎有InnoDB和NDB。事务的实现就是实现事物的基本要素,事务的隔离性通过锁实现,事务的一致性、持久性、原子性依靠事务日志
事务持久性和原子性的实现
InnoDB通过重做日志和日志缓冲实现;在事务开始时首先将事务写入日志缓冲中,并在事务提交前将日志缓冲中的数据持久化到磁盘中。当事务提交之后,事务对数据的修改才会从缓存中慢慢持久化到磁盘中。如数据从缓冲中持久化到磁盘中发生异常,也可以通过重做日志来恢复数据库状态继续执行事务,确保事务弄够完整的执行完毕并将数据持久化到磁盘中。
事务一致性的实现
InnoDB在事务执行的过程中记录下回滚日志,也就是数据被修改前的状态,当需要进行回滚是就根据回滚日志将数据恢复。单个事务的回滚只会回滚当前事务做的操作不会影响其他事务。
Mysql日志种类
- 错误日志:记录出错信息
- 查询日志:记录所有查询请求的信息,无论是否正确执行
- 长查询日志:当查询时间到一定时就会被记录到长查询日志中
- 中继日志:存在在主从服务器中,从服务器中中继日志与主服务器同步状态
- 二进制日志:对数据库的所有操作均记录在二进制日志中
- 事务日志:完成事务基本要素的日志,包括重做日志和回滚日志
Mysql对分布式事务的支持
InnoDB对分布式事务的支持。
分布式事务设计到三个模型。
- 应用程序(定义事务的边界,指定哪些操作要做事务控制)
- 资源管理器(提供访问事务的方法,一般一个资源管理器就是一个数据库)
- 事务管理器(协调全局事务的执行)
流程分两步
- 所有事务节点告诉事务管理器自己已经做好准备
- 由事务管理器来控制每个结点是提交事务还是回滚事务,只要有一个结点失败就需要全部回滚
mysql事务常见面试题
事务的隔离级别有哪些?MySQL的默认隔离级别是什么?
什么是幻读,脏读,不可重复读呢?
MySQL事务的四大特性以及实现原理
MVCC熟悉吗,它的底层原理?
Mysql的锁机制
锁机制:计算机协调多进程或者线程并发访问某一资源的机制
在数据库中处理常见的计算机资源如CPU、GPU、IO等,数据也是一种多用户共享的资源。Mysql的锁机制就是为了保证共享数据在并发访问时变得有序所涉及的一种控制规则
锁分类
- 按照数据操作类型分类
-
- 读锁(共享锁):对同一个数据,允许多个读操作同时进行
- 写锁(排它锁):对同一个数据,仅允许写锁拥有者操作
- 按照数据操作粒度进行分类
为了保证数据库在高并发情况下的响应度,每次尽可能缩小锁定范围越能提高响应度,但是管理锁需要消耗资源因此数据库系统需要再高并发响应和系统性能方面做取舍,进而产生出了锁粒度的概念
-
- 表级锁:开销小,加锁快,并发响应低(MyISAM、Memory存储引擎采用)
- 行级锁:开销大,加锁慢,并发响应高(InnoDB默认使用行级锁,同样支持表级锁)
- 页面锁:开销和加锁都介于表级锁和行级锁之间
使用场景:查询多修改少使用表级锁,反之行级锁
MyISAM表锁
表锁有两种模式
- 表共享读锁:不阻塞其他用户对同一张表的读请求,但是会阻塞写请求
- 表独占写锁:阻塞其他用户的读、写请求
MyISAM表的写操作是串行的,当某线程获得写锁后仅当前线程可以对该表进行读写操作,在默认的情况下写锁的优先级比读锁高,当一个锁释放时存储引擎会优先查看写锁队列
InnoDB的行锁
两种类型的行锁
- 共享锁:允许一个事务读一行,组织其他事务获取排它锁
- 排它锁:允许获得排它锁事务对数据进行更新,组织其他事务获得共享锁和排它锁
为了允许行锁和表锁共存,实现多颗粒度机制,innodb还有两种意向锁
- 意向共享锁:事务打算加行共享锁前必须先获取到该表的意向共享锁
- 意向排它锁:事务打算给行加排它锁前必须先获取到该表的意向排它锁
注意:索引失效会导致行锁失效,变为获取表锁
加锁机制
乐观锁和悲观锁是两种并发控制的思想,都是用于解决更新丢失的问题
乐观锁
乐观锁任务数据处理的过程不会出现冲突,在处理的过程中不加锁,只有在更新数据的时候根据版本号或者时间戳判断是否产生了冲突,有就进行处理,没有就提交事务。
悲观锁
悲观锁任务在进行数据处理时一定会发生错误,所以在进行数据处理前就会进行加锁控制防止并发问题
锁模式(InnoDB有三种行锁的算法)
- 记录锁:单个行记录上锁。对索引项加锁,锁定所有符合条件的行,其他事务就不可在进行修改和删除
- 间隙锁:使用范围查询时,InnoDB会对符合条件的记录进行加锁。对于键值在条件范围内但并不存在的记录并成为间隙,这些间隙也会被加锁。加锁的范围为第一个记录前的间隙和最后一个记录后的间隙加锁,并不包含索引项本身,这样保证其他事务不能再该范围内插入数据,防止别的事务增加幻影行
- 临键锁:临键锁是记录锁和间隙锁的组合,既锁定索引项也锁定索引范围内的所有数据行。也防止了幻读的出现
Next-Key 可以理解为一种特殊的间隙锁,也可以理解为一种特殊的算法。通过临建锁可以解决幻读的问题。 每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。需要强调的一点是,InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。
对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
死锁
两个或者多个事务相互争夺同一资源导致相互等待的现象
死锁出现的必要条件
- 互斥条件:某资源一次只能分配给一个线程
- 请求和保留条件:线程至少占有了一项资源并会提出获取新资源的请求,若要获取的资源无法获取也不会释放自己现在占有的其他资源
- 不剥夺条件:线程持有的资源只能由线程自己使用完后释放,不能被剥夺
- 环路等待条件:发生死锁时必然存在一个多进程资源占用的环形链设有n个进程,那么就会有n1等待n2,n2等待n3,nn等待n0的情况
死锁的原因
- 两个或者多个事务以不同顺序锁定相同资源,就可能导致死锁产生
-
- 存在数据1、2以及两个事务A、B。A事务需要先修改1才修改数据2,B事务需要先修改数据2再修改数据1。事务A首先获得数据1的排他锁后切换至事务B执行,B事务获得数据2的排它锁修改完数据准备获取数据1的排它锁,此时发现A事务占有了数据1的排它锁,于是切换至事务A继续执行,A事务处理完1数据后要获取2数据的排它锁,此时发现排它锁在事务B上,此时出现了死锁现象,两个事务无限等待。
- 两个或者多个事务并发锁定同一个资源可能产生死锁
-
- 存在事务A、B以及数据1。A事务先查询数据1再对数据1进行修改,B事务需要修改数据1。首先A事务开始执行,获取到共享锁后切换事务B执行,B事务获取到排它锁后发现此时存在共享锁因此进入队列等待,切换A事务继续执行,A事务查询完1数据后准备修改数据1要获取排它锁但是被B事务获取了,因此无法进行修改。此时出现死锁现象
死锁的检测
InnoDB能够检测到死锁的循环依赖并返回错误
死锁恢复
死锁发生以后只有部分或者完全回滚一个事物才能打破死锁,InnoDB处理死锁的方式是将持有最少行排它锁的事务进行回滚。因此事务性应用程序需要考虑发生死锁后如何处理,多数情况下只需要重新执行因死锁回滚的事务即可。
外部锁的死锁检测
一般情况下innoDB都能检测到死锁的出现,但是涉及到外部所或者表锁的情况下有可能无法检测出,此时就需要设置锁等待超时参数
死锁的影响
死锁并不会导致严重错误的出现而会影响性能,因为有死锁检测机制会对死锁中的事务进行回滚解除死锁状态,有时禁用死锁检测的效率会没有锁等待超时参数
MyISAM避免死锁
MyISAM会一次性获取sql中需要的锁,所以不会出现死锁的情况
InnoDB避免死锁
- 为了避免在单个InnoDB表并发更新多个数据出现死锁,可以在事务开始的时候对预期要修改的列使用selectforupdate语句来获得需要的锁(尽量在同时获取到事务需要的排它锁)
- 在事务中如果要更新某数据尽可能直接获取排它锁,而不是先获取共享锁再升级为排它锁,如果是以升级的方式就可能因为在升级前排它锁被其他事务获取导致死锁
- 在事务中如果需要修改或者锁定多个表应该尽可能按照相同的顺序使用加锁语句
- 尽量不出现锁升级的情况容易出现死锁
- 改变事务的隔离级别
如果出现死锁,可以用 show engine innodb status; 命令来确定最后一个死锁产生的原因。返回结果中包括死锁相关事务的详细信息,如引发死锁的 SQL 语句,事务已经获得的锁,正在等待什么锁,以及被回滚的事务等。据此可以分析死锁产生的原因和改进措施。
Mysql锁常见面试题
数据库的乐观锁和悲观锁?
MySQL 中有哪几种锁,列举一下?
MySQL中InnoDB引擎的行锁是怎么实现的?
MySQL 间隙锁有没有了解,死锁有没有了解,写一段会造成死锁的 sql 语句,死锁发生了如何解决,MySQL 有没有提供什么机制去解决死锁
Mysql调优
最好的调优的尽量避免出现影响mysql性能的场景,因此首先了解一下影响mysql性能的因素
影响mysql性能因素
- 业务契合度
- 存储定位
-
- 不适合放进mysql的数据
-
-
- 二进制多媒体数据
- 流水队列数据
- 超大文本数据
-
-
- 需要放进缓存的数据
-
-
- 访问多修改少的数据
-
- 系统设计
-
- 尽量减少访问请求
- 硬件性能
性能分析
要对查询进行分析就得了解到优化器生成的执行计划,其中包含查询如何进行操作,如使用什么索引,执行语句的顺序等。
优化器
优化器是mysql服务层中专门优化SELECT语句查询效率的模块,它主要的作用是分析系统中收集到的数据以此生成它认为最优的执行计划
工作流程
- 由解析器对语句进行分类,当识别为SELECT类型语句时就将查询交给优化器进行优化
- 优化器首先将语句中的常量表达式进行预算,并直接用常量进行替换
- 将查询中的无用条件进行去除并调整语句结构
- 查看查询条件是否存在Hint(查询优化提示:协助优化器生成执行计划;如强制使用某个索引、现执行某个语句等等)语句,如果不存在或者Hint语句不足生成执行计划,优化器就会去计算设计到对象的统计数据并作为依据生成执行计划
Mysql常见的性能分析手段
- 慢查询日志:查看那些查询执行速度很慢对这些语句进行优化
- 查看执行计划:对SELECT语句使用EXPLIAN命令查看执行计划
- profiling分析:
- show命令:如查看表的查询次数、插入次数等等来分析
执行计划Explain
执行计划是由优化器生成的,该计划列出了一些列参数来说明mysql是如何执行SELECT语句的查询
关键信息
- 读表顺序
- 数据读取的操作类型
- 可使用的索引
- 实际使用的索引
- 表之间的引用关系
- 优化器对每张表查询了多少行
参数
- id序号:SELECT语句操作表的顺序,id大的先执行,id相同则从上往下执行
- 查询类型:
Mysql调优常见面试题
日常工作中你是怎么优化SQL的?
SQL优化的一般步骤是什么,怎么看执行计划(explain),如何理解其中各个字段的含义?
如何写sql能够有效的使用到复合索引?
一条sql执行过长的时间,你如何优化,从哪些方面入手?
什么是最左前缀原则?什么是最左匹配原则?