MySQL

慢查询

表象:页面加载过慢、接口压测响应时间过长(超过1s)

1. MySQL中,如何定位慢查询?
候选人:
嗯,我们当时在做压力测试时发现有些接口响应时间非常慢,超过了2秒。因为我们的系统部署了运维监控系统Skywalking,在它的报表展示中可以看到哪个接口慢,并且能分析出接口中哪部分耗时较多,包括具体的SQL执行时间,这样就能定位到出现问题的SQL。
如果没有这种监控系统,MySQL本身也提供了慢查询日志功能。可以在MySQL的系统配置文件中开启慢查询日志,并设置SQL执行时间超过多少就记录到日志文件,比如我们之前项目设置的是2秒,超过这个时间的SQL就会记录在日志文件中,我们就可以在那里找到执行慢的SQL。
分析慢查询
  • 通过key和key_len检查是否命中了索引(索引本身存在是否有失效的情况)
  • 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
  • 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
优化慢查询
  • 索引
    • 索引(index)是帮助MySQL高效获取数据的数据结构(有序)
    • 提高数据检索的效率,降低数据库的IO成本(不需要全表扫描)
    • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
  • 索引的底层结构

    • 采用B+树的数据结构存储索引
      • 路径更短
      • B+树磁盘读写代价更低, 只有叶子节点存储数据
      • 便于扫库和区间查询(叶子节点是双向链表)
  • 聚集索引与二级索引

    • 聚集索引:
      • 数据存储在索引的叶子节点中
    • 二级索引(非聚集索引):
      • 索引的叶子节点只存储对应的主键值
      • 二级索引需要回表查询–通过叶子节点的主键值在聚集索引中找到对应的数据
  • 覆盖索引

    • 指查询中使用了索引且索引中包含了需要返回的列

      • 使用id查询直接用聚集索引一次索引扫描直接返回数据, 性能高
      • 如果返回到列中没有创建索引, 有可能会触发回表查询, 所以尽量避免使用select *
    • MySQL超大分页处理

      • 在数据量比较大时, 如果进行limit分页查询, 查询越往后, 分页查询效率越低

      • 优化思路:

        • 通过创建覆盖索引能够比较好地提高性能, 可以通过覆盖索引加子查询的形式进行优化

        • select *
          from tb_sku t,
          (select id from tb_sku order by id limit 9000000,10) a
          where t.id = a.id;
          
  • 索引创建

    • 针对数据量较大, 且查询比较频繁的表建立索引 (单表超过10万数据)
    • 针对于常作为查询条件, 排序, 分组操作的字段建立索引
    • 尽量选择区分度高的列作为索引(列数据差异大)
    • 尽量使用联合索引, 减少单列索引, (索引中包含的key更多的), 可以覆盖索引, 避免回表查询
    • 控制索引数量
    • 对于不能够存储NULL值的索引, 用NOT NULL约束
  • 索引失效

    • 失效情况
      • 违反最左前缀法则
      • 范围查询右边的列,不能使用索引
      • 不要在索引列上进行运算操作,
      • 索引将失效字符串不加单引号,造成索引失效。
      • (类型转换)以%开头的Like模糊查询,索引失效
sql的优化
  • 表的设计优化(参考优化手册)
    • 设置合适的数值(tinyint, int, bigint)
    • 设置合适的字符串类型(char , varchar)
  • SQL语句优化
    • 避免直接使用select *
    • 避免造成索引失效的写法
    • 使用union all , 避免union的多一次过滤
    • 避免在where子句中对字段进行表达式操作
    • left 或right join时将小表放在外面, 减少连接次数(外连接不会调整连接次序)
  • 主从复制, 读写分离
    • 写操作不会影响查询的效率
事务

事务时一组操作的集合, 是不可分割的工作单位, 事务会把所有的操作作为一个整体一起向系统提交或撤销操作, 这些操作要么同时成功要么全部失败

  • 事务的特性
    • Atomicity 原子性, 事务时不可分割的最小单元
    • Consistency一致性, 事务完成时必须使所有数据保持一致状态
    • Isolation隔离性, 事务在不受外部并发操作影响的独立环境下运行
    • Durability持久性, 事务一旦提交或回滚, 它对数据库中的数据的改变就是永久的
  • 并发事务
    • 问题:
      • 脏读: 一个事务读到另外一个事务还没有提交的数据
      • 不可重复读: 同一事务内, 两次读取同一行数据, 第二次读到的值变化了, 影响的时同一行的数据
      • 幻读:同一事务内, 两次查询相同条件, 结果集的行数变化了, 影响的时整个结果集的行数
    • 解决方案: 对事物进行隔离
      • 可重复读(默认)
      • 串行化
    • 缓冲池(buffer pool): 主内存中的一个区域, 存储缓存的是经常操作的磁盘中缓存的数据, 在执行SQL操作时, 先操作缓冲池中的数据, 如果池中未查找到需要的数据, 则从磁盘中加载并缓存
    • 数据页: 是InnoDB存储引擎磁盘管理的最小单元, 存储的是行数据.
    • redo log:
      • 重做日志, 记录的是事务提交时数据也的物理修改, 用来实现事务的持久性
      • 当事务提交后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘发生错误时进行数据恢复使用
    • undo log:
      • 回滚日志, 用于记录数据修改前的信息
      • 提供回滚和MVCC(多版本并发控制), 实现事务的一致性和原子性
redo log: 记录的是数据页的物理变化,服务宕机可用来同步数据
undo log :记录的是逻辑日志,当事务回滚时,通过逆操作恢复原来的数据
redo log保证了事务的持久性,undo log保证了事务的原子性和一致性
好的,事务中的隔离性是如何保证的呢?
锁:排他锁(如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁)
mvcc : 多版本并发控制
MVCC

Multi-Version Concurrency Control 多版本并发控制, 指维护一个数据的多个版本, 使得读写操作没有冲突

MySQL中的多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突

  • 隐藏字段:

    • trx_id(事务id),记录每一次操作的事务id,是自增的
    • roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
  • undo log:

    • 回滚日志,存储老版本数据
    • 版本链:多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表
  • readView解决的是一个事务查询选择版本的问题

    • 根据readView的匹配规则和当前的一些事务id判断该访问那个版本的数据

    • 不同的隔离级别快照读是不一样的,最终的访问的结果不一样

      • RC :每一次执行快照读时生成ReadView

      • RR:仅在事务中第一次执行快照读时生成ReadView,后续复用

主从同步原理
  • 核心是二进制日志
    • 二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。
  • 主库在事务提交成功后, 会将数据变更记录在二进制文件BINLOG中->从库读取主库的BINLOG文件, 并且写入到从库的中继日志RelayLog中-> 从库重做中继日志中的语句来改变从库的数据
分库分表
  • 时机:
    • 前提,项目业务数据逐渐增多,或业务发展比较迅速
    • 优化已解决不了性能问题(主从读写分离、查询索引…)
    • IO瓶颈(磁盘IO、网络IO)、CPU瓶颈(聚合查询、连接数太多)
  • 垂直分库:
    • 以表为依据, 根据业务将不同表拆分到不同库中
    • 按业务对数据分级管理维护
  • 垂直分表:
    • 以字段为依据, 分局字段属性将不同字段拆分到不同表中
      • 把不常用的字段单独放在一张表
      • 把大字段拆分
    • 冷热数据分离, 减少IO过渡争抢, 量表互不影响
  • 水平分库
    • 将一个库的数据拆分到多个库中
    • 解决单库大数量高并发的问题
    • 提高系统稳定性可用性
  • 水平分表
    • 将一个表数据拆分到多个表中
    • 优化单一表数据量过大而产生的性能问题;
    • 避免IO争抢并减少锁表的几率;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值