MySQL

1 优化

1.1 在MySQL中,如何定位慢查询?

方案一: 开源工具

  1. 调式工具:Arthas
  2. 运维工具: Prometheus , Skywalking

方案二:MySQL 自带慢日志

慢查询日志记录了所有的执行时间超过指定参数的所有SQL语句的日志

如果要开启慢查询日志,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
#开启MySQL慢日志开关
slow_query_log = 1 
# 设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time = 2 

配置完成后,通过重启mysql

1.2 SQL语句执行很慢,如何分析?

可以采用EXPLAIN或者DESC命令获取MySQL如何执行信息。

2 索引

索引( index )是帮助 MySQL 高效获取数据的数据结构 ( 有序 ) 。在数据之外,数据库系统还维护着满足特定查找算法的数据结构( B+ 树),这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

mysql主要是是使用B+树作为索引

B-Tree , B 树是一种多叉路衡查找树,相对于二叉树, B 树每个节点可以有多个分支,即多叉。

以一颗最大度数( max-degree )为 5(5 阶 ) 的 b-tree 为例,那这个 B 树每个节点最多存储 4 个 key

image

B+树是在BTree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+ Tree实现其索引结构

image

B树和B+树的对比:

  1. 磁盘读写代价B+树更低
  2. 查询效率B+更加稳定
  3. B+ 树便于扫库和区间查询

2.1 什么是聚簇索引?什么是非聚簇索引?

分类 含义 特点
聚集索引 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 必须有,而且只有一个
非聚集索引 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 可以存在多个

聚集索引选取规则:

  1. 如果存在主键,主键索引就是聚集索引
  2. 如果不存在主键,将使用第一个唯一索引作为聚集索引
  3. 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引

image

image​​

2.2 什么叫做覆盖索引?

覆盖索引是指查询使用了索引,并且需要返回的列在该索引中已经全部能够找到。

image

使用覆盖索引进行超大分页处理。

image

2.3 索引创建原则有哪些?

  1. 针对数据量较大,且查询比较复杂的表建立索引。 单表超过10万数据
  2. 针对常作为查询条件(where) 、排序(order by) 、分组(group by) 操作的字段建立索引
  3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
  4. 如果是字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引
  5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
  6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代码就越大,会影响增删改的效率
  7. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确认哪个索引最有效的用于查询

2.4 什么情况下索引会失效?

  1. 违反最左前缀法则

    如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左列开始,并且不跳过索引中的列,匹配最左前缀法则,

    image

    image

  2. 范围查询右边的列,不能使用索引。

  3. 不要在索引列上进行运算操作,索引将失效

  4. 字符串不加单引号,造成索引失效(类型转换)

  5. 以%开头的Like模糊查询,索引失效。如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

2.5 谈谈你对sql的优化的经验?

  1. 表的设计优化

    1. 比如设置合适的数值(tinyint int bigint) ,要根据实际情况选择
    2. 比如设置合适的字符串类型(char 和 varchar)char定长效率高,varchar可变长度,效率稍低
  2. sql语句的优化

    1. select 语句务必指明字段名称(避免直接使用select * )
    2. SQL语句要避免造成索引失效的写法
    3. 尽量使用union all 代替union, union会多一次过滤,效率低
    4. 避免在where子句中对字段进行表达式操作
    5. Join优化,能用innerjoin 就不用 left join right join,如必须使用一定要以表为驱动,内连接会对两个表进行优化,优先把小表放到外边,把大表放到里面。left join 或 right join ,不会重新调整顺序
  3. 主从复制,读写分离

    1. 如果数据库的使用场景都的操作比较多的时候,为了避免写的操作所造成的性能影响,可以采用读写分离结构,读写分离解决的是,数据库的写入,影响了查询的效率

3 事务

3.1 事务的特性是什么,可以详细说明一下吗?

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
  1. 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  2. 一致性(Consistency):事务完成时,必须使所有的数据都保持一致的状态。
  3. 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  4. 持久性(Durability):事务一旦提交或回滚,他对数据库中的数据的改变就是永久的。

3.2 并发事务带来哪些问题?怎么解决这些问题?MySQL的默认隔离级别?

  1. 并发事务问题

|问题|描述||
|脏读|一个事务读到另一个事务还没有提交的数据||
|不可重复读|一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读||

幻读 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了幻影。
  1. 怎么解决并发事务的问题

image

  1. 默认隔离级别是:可重复读

3.3 undo log 和 redo log的区别?

  • 缓冲池:主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定的频率刷新到磁盘,从而减少磁盘IO,加快处理速度
  • 数据页:是InnoDB存储引擎磁盘管理的最小单元,每个页的大小默认为16KB,页中存储的是行数据。
  1. redo log

    重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。

    该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中,当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到次磁盘,发生错误时,进行数据恢复使用。

  2. undo log

    回滚日志,用于记录数据被修改前的信息,作用包括两个: 提供回滚和MVCC(多版本并发控制)。undo log 和redo log记录物理日志不一样,它是逻辑日志。

    • 可以认为当delete一条记录时,undo log 会记录一条对应的insert记录,反之亦然

    • 当update一条记录时,他记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。

3.4 事务中的隔离性是如何保证的呢?

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

MVCC-实现原理

  • 记录中的隐藏字段

    |隐藏字段|描述||
    |DB_TRX_ID|最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID||
    |DB_ROLL_PTR|回滚指针,指向这条记录的上一个版本,用于配合undo log ,指向上一个版本||

    DB_ROW_ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段
  • undo log

    回滚日志,在 insert 、 update 、 delete 的时候产生的便于数据回滚的日志。

    当 insert 的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被立即删除。

    而 update 、 delete 的时候,产生的 undo log 日志不仅在回滚时需要, mvcc 版本访问也需要,不会立即被删除。

  • undo log版本链

  • readview

    ReadView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id

  • 当前读

    读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行枷锁。

  • 快照读

    简单的select(不加锁)就是快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读

    • Read Committed:每次select都生成一个快照读
    • Repeatable Read: 开启事务后第一个select语句才是快照读的地方

3.5 MySQL主从原理

MySQL主从复制的核心就是二进制日志

二进制日志( BINLOG )记录了所有的 DDL (数据定义语言)语句和 DML (数据操纵语言)语句,但不包括数据查询( SELECT 、 SHOW )语句。

3.6 分库分表

  1. 拆分策略

    image

    1. 垂直分库

      以表为依据,根据业务将不同表拆分到不同库中。

      1. 按业务对数据分级管理
    2. 垂直分表

      以字段为依据,根据字段属性将不同字段拆分到不同表中

      拆分规则:

      1. 把常用的字段单独放在一张表
      2. 把text,blob等大字段拆分出来放在附表中

      特点:

      1. 冷热数据分离
      2. 减少IO过度争抢,两表会不影响
    3. 水平分库

      将一个库的数据分到多个库中

      特点:

      1. 解决了单库大数量,高并发的性能瓶颈
      2. 提高了系统的稳定性和可用性
    4. 水平分表

      将一个表的数据拆分到多个表中(可以在同一个库中)

      特点:

      1. 优化单一表数据量过大而产生的性能问题
      2. 避免IO争抢并减少锁表的几率