MySQL
MySQL
1 优化
1.1 在MySQL中,如何定位慢查询?
方案一: 开源工具
- 调式工具:Arthas
- 运维工具: 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
B+树是在BTree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+ Tree实现其索引结构
B树和B+树的对比:
- 磁盘读写代价B+树更低
- 查询效率B+更加稳定
- B+ 树便于扫库和区间查询
2.1 什么是聚簇索引?什么是非聚簇索引?
分类 | 含义 | 特点 |
---|---|---|
聚集索引 | 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 | 必须有,而且只有一个 |
非聚集索引 | 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 | 可以存在多个 |
聚集索引选取规则:
- 如果存在主键,主键索引就是聚集索引
- 如果不存在主键,将使用第一个唯一索引作为聚集索引
- 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
2.2 什么叫做覆盖索引?
覆盖索引是指查询使用了索引,并且需要返回的列在该索引中已经全部能够找到。
使用覆盖索引进行超大分页处理。
2.3 索引创建原则有哪些?
- 针对数据量较大,且查询比较复杂的表建立索引。 单表超过10万数据
- 针对常作为查询条件(where) 、排序(order by) 、分组(group by) 操作的字段建立索引
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
- 如果是字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引
- 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
- 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代码就越大,会影响增删改的效率
- 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确认哪个索引最有效的用于查询
2.4 什么情况下索引会失效?
违反最左前缀法则
如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左列开始,并且不跳过索引中的列,匹配最左前缀法则,
范围查询右边的列,不能使用索引。
不要在索引列上进行运算操作,索引将失效
字符串不加单引号,造成索引失效(类型转换)
以%开头的Like模糊查询,索引失效。如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
2.5 谈谈你对sql的优化的经验?
表的设计优化
- 比如设置合适的数值(tinyint int bigint) ,要根据实际情况选择
- 比如设置合适的字符串类型(char 和 varchar)char定长效率高,varchar可变长度,效率稍低
sql语句的优化
- select 语句务必指明字段名称(避免直接使用select * )
- SQL语句要避免造成索引失效的写法
- 尽量使用union all 代替union, union会多一次过滤,效率低
- 避免在where子句中对字段进行表达式操作
- Join优化,能用innerjoin 就不用 left join right join,如必须使用一定要以表为驱动,内连接会对两个表进行优化,优先把小表放到外边,把大表放到里面。left join 或 right join ,不会重新调整顺序
主从复制,读写分离
- 如果数据库的使用场景都的操作比较多的时候,为了避免写的操作所造成的性能影响,可以采用读写分离结构,读写分离解决的是,数据库的写入,影响了查询的效率
3 事务
3.1 事务的特性是什么,可以详细说明一下吗?
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致的状态。
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,他对数据库中的数据的改变就是永久的。
3.2 并发事务带来哪些问题?怎么解决这些问题?MySQL的默认隔离级别?
- 并发事务问题
|问题|描述||
|脏读|一个事务读到另一个事务还没有提交的数据||
|不可重复读|一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读||
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了幻影。 |
---|
- 怎么解决并发事务的问题
- 默认隔离级别是:可重复读
3.3 undo log 和 redo log的区别?
- 缓冲池:主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定的频率刷新到磁盘,从而减少磁盘IO,加快处理速度
- 数据页:是InnoDB存储引擎磁盘管理的最小单元,每个页的大小默认为16KB,页中存储的是行数据。
redo log
重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中,当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到次磁盘,发生错误时,进行数据恢复使用。
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 分库分表
拆分策略
垂直分库
以表为依据,根据业务将不同表拆分到不同库中。
- 按业务对数据分级管理
垂直分表
以字段为依据,根据字段属性将不同字段拆分到不同表中
拆分规则:
- 把常用的字段单独放在一张表
- 把text,blob等大字段拆分出来放在附表中
特点:
- 冷热数据分离
- 减少IO过度争抢,两表会不影响
水平分库
将一个库的数据分到多个库中
特点:
- 解决了单库大数量,高并发的性能瓶颈
- 提高了系统的稳定性和可用性
水平分表
将一个表的数据拆分到多个表中(可以在同一个库中)
特点:
- 优化单一表数据量过大而产生的性能问题
- 避免IO争抢并减少锁表的几率