MySQL八股(自用)
MySQL
定位慢查询
1.聚合查询
2.多表查询
3.表数据量过大查询
4.深度分页查询
MySQL自带慢日志
开启慢查询日志,配置文件(/etc/my.cnf)
开启慢日志,设置慢日志的时间
用EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息
key 当前sql实际命中的索引
key_len索引占用的大小
extra 出现condition需要回表查询(添加索引或者修改返回字段)
MySQL支持的存储引擎
innoDB支持事务安全,支持表锁,行锁(另外两种不支持),支持外键
innoDB 兼顾高可用和高性能的通用存储引擎,MySQL默认的存储引擎
DML操作遵循ACID模型,支持事务
行级锁
支持外键
索引(有序的数据结构)
B+树
相比B树,实现外存储索引结构
优势:磁盘读写代价低,查询效率稳定,
便于扫库和区间查询(叶子结点组成一个有序的双向查询链表)
聚簇索引 将数据存储与索引放到一起,叶子节点保存了行数据 必须有,唯一
二级索引 将数据与索引分开存储,叶子节点关联对应的主键 可以有多个
如果存在主键,主键索引就是聚簇索引
不存在主键,唯一索引为聚簇索引
都不符合,innoDB自动生成一个rowid作为隐藏的聚簇索引
覆盖索引
索引中能找到所有需要返回的值
聚簇索引都是覆盖索引
非覆盖索引需要回表查询
MySQL超大分页可以使用覆盖索引
数据量大,limit分页查询,越靠后,分页查询效率越低
分页查询优化:创建覆盖索引+子查询
先通过子查询找到这个范围里的所有id
再通过id查询聚簇索引(覆盖索引)
创建索引原则
1.查询频繁的表
2.常作为查询条件、排序、分组操作的字段建立索引
3.区分度高的列作为索引,尽量建立唯一索引
4.针对字段特点建立索引,比如建立前缀索引
5.使用联合索引,减少单列索引,避免回表
6.控制索引的数量,维护代价大,影响增改查效率
7.不能存储null值的索引列会被优化器优先用于查询
索引失效
1.违反最左前缀法则
索引多列从索引的最左列开始,不跳过中间列
2.范围查询的右边的列不能使用索引
3.不要在索引上进行运算操作,索引失效 subString
4.字符串不加单引号,索引失效(查询优化器进行类型转换)
5.%开头的Like头部模糊匹配失效,尾部模糊匹配不失效
sql的优化方案
表的设计优化:设置合适数值,设置合适字符串类型
sql语句优化
避免SELECT * 务必指明字段
避免索引失效的写法
尽量用union all代替union union会多一次过滤
避免where子句对字段进行表达式操作
能用内连接(inner join)不用外连接(left right join)
使用时一定以小表作为驱动
内连接会对两个表进行优化,优先把小表放到外面,大表放到里面
left right join不会重新调整顺序
主从复制、读写分离
读操作比较多
数据库的写入影响读的效率
事务的特性 ACID
事务:一组操作的集合,不可分割的工作单位,同时成功或同时失败
A原子性:不可分割的最小操作单元,全部成功或全部失败
C一致性:事务完成,所有数据保持一致性
I隔离性:不受外部并发操作影响
D持久性:事务一旦提交或者回滚,对数据的改变就是永久的
并发事务问题:脏读,不可重复读,幻读
隔离级别:读未提交,读已提交,可重复读,串行化
脏读:一个事务读到另一个事务没提交的数据
不可重复读:一个事务对同一记录的读取结果不同(修改)
幻读:查询数据时,没有对应的数据行,插入数据时,这行数据又出现了(插入)
缓冲池:内存中,缓存磁盘上经常操作的真实数据
执行增删查改操作先操作缓冲池里的数据(没数据从磁盘加载)
以一定频率刷新磁盘,减少磁盘io
数据页:innoDB存储引擎磁盘管理的最小单元
每个页的大小默认16kb,页中缓存的是行数据
redo log(事务的持久性)
重做日志,记录事务提交时的数据页的物理修改,实现事务的持久化
该日志文件由两部分组成:
重做日志缓冲:内存中
重做日志文件:磁盘中
事务提交后所有修改信息都存在日志文件中,
用于刷新脏页到磁盘,磁盘错误时,进行数据恢复
redo log 记录物理日志
undo log 是逻辑日志
undo log(事务的原子性和一致性)
回滚日志,记录数据修改前的信息
提供回滚,MVCC多版本并发控制
delete一条记录,undo log记录一条对应的insert记录
update一条记录,记录一条相反的update记录
执行rollback可以根据undo log中的逻辑记录回滚
undo log可以实现事务的一致性和原子性
事务隔离性
排他锁
mvcc:多版本并发控制(允许多个事务访问数据库)
维护一个数据的多个版本,读写操作没有冲突
依赖于数据库中记录的隐式字段、undo.log日志、readView
隐藏字段:
最近修改事务id,记录插入这条记录,或最后一次修改的事务id
回滚指针:指向这条记录的上一个版本,用于配合undo.log
隐藏主键:表结构没有指定主键,会自动生成该字段
undo log
回滚日志:insert,update,delete
insert对现有记录没有影响
update,delete对现有记录有影响
insert产生的undo log日志只在回滚的时候需要,事务提交之后可以被立即删除
update,delete 产生的undo log日志不止回滚时需要
mvcc版本访问时也需要,因为有的线程会访问旧版本,不会立即删除
undo log版本链
不同事务或相同事务对同一条记录进行修改,
导致该记录的undolog生成一条记录版本链表
链表头部是最新的旧记录,尾部是最早的旧记录
readview
读视图 快照读
记录维护当前活跃的未提交的事务的id
当前读
读取的是记录的最新版本,对读取的记录加锁
保证其他事务不能修改当前事务 共享锁/排他锁
快照读
简单的select不加锁就是快照读
读取的是记录数据的可见版本,也可能是历史版本,不加锁,非阻塞读
每次select,都生成一个快照读
开启事务后的第一个select语句是快照读的地方
四个核心字段
当前活跃事务id集合
最小活跃事务id
预分配事务id,就是最大事务id+1(事务id是自增的)
ReadView创建者的事务id
不同隔离级别,生成ReadView的时机不同
在事务中每一次执行快照读时生成ReadView(RC模式)
仅在事务第一次执行快照读时生成ReadView,后续复用该ReadView(RR模式)
主从同步
核心:二进制日志
BINLOG记录了所有DDL(数据定义语言)和DML(数据操纵语言)
不包括SELECT,SHOW语句
master主库:事务提交后,把数据变更记录在二进制日志文件中
从库读取主库的二进制日志文件,写入从库的中继日志
slave重现中继日志中的操作
分库分表
单表数据量达到1000w或20G
优化解决不了性能问题(主从,索引)
io瓶颈(磁盘,网络),cpu瓶颈(聚合查询,连接太多)
垂直拆分
垂直分库:将不同的业务拆分到不同的库中
高并发,提高磁盘io和数据量连接数
垂直分表:字段为依据,将不同字段拆分到不同表
不常用字段放到一张表
将大字段拆分成附表
冷热数据分离
减少io过滤争抢,两表互不影响
水平拆分
水平分库:将一个库数据拆分到多个库中
路由规则:根据id节点取模、范围路由
解决单库大数据量,高并发的性能瓶颈
水平分表:将一个表的数据拆分到多个表中
优化单一表数据量大
避免io争抢导致锁表几率
中间件:sharding-sphere
mycat