导图社区 MySQL
MySQL——包括数据类型,性能优化,事物,三大特性的知识点内容,适用于java面试的小伙伴~
编辑于2022-07-28 15:01:02MySQL
数据类型
数据类型的优化
选择类型小的类型;数据类型小的数据速度块,占用磁盘少
避免null值,null使得索引难优化
Varchar
可变类型/如果update时 将字段变长,并且此时当前页没有更多的空间存储,innodb 需要分裂页,使此行可以放入当前页内
适合
字符串最大长度大于平均长度很多
列更新少
VARCHAR(5)和VARCHAR(200)
存储5个字节以下的字段,占用空间是一样的
MySQL通常会分配固定大小的内存块来保存内部值所以推荐只分配真正需要的空间
性能优化
Explain
select_type
type
system
const 用于比较primary key或者unique 索引速度快,当表只有一行时,显示的时system
eq_ref
ref
range
index
All
possible_keys
key
命中的索引
key_len
使用索引的长度,越小越好
ref
rows
查询的行数,越小越好
Extra
using where using filesort等
索引
类型
B+ tree 索引
聚簇索引
叶子节点是数据
为什么主键索引要自增
B+树存储数据,数据相邻的两条数据
放在一起,要是自增,每次插入数据
按顺序插入,每页写满会开辟新的一页,
要是不递增则会频繁的插入,移动数据
到不同页
辅助索引
叶子节点是主键的值
先查询到主键的值在到主索引(聚簇索引)中查找数据 这叫回表
hash 索引
全文索引
查找文本中的关键词,一般使用倒排索引实现
innodb 在Mysql 5.6.4 中开始支持全文索引
MyISAM 引擎支持,这也是它的优点
空间数据索引
MyISAM 引擎支持,用于地理位置存储
索引优化
联合索引
最左匹配
多个查询条件时 ,联合索引比多个单索引性能要好
前缀索引
主要适用于TXET,BLOG 这种大长度的列,索引开始部分字符
覆盖索引
索引包含所有需要查询的字段的值
独立的列
进行查询时,索引不能是表达式一部分,也不能是函数的参数,否则无法使用索引
索引顺序
选择性强的索引放在前面(提前过滤大部分数据)选择性:不重复的索引值/记录总数,最大值为1 即,每个数据都是不同的
最左匹配原则 遇到>、<、between、like 停止匹配
=和in可以乱序,mysql查询优化器可以帮优化成索引识别的方式
选择区分度(选择性)高的字段做索引
隐式转换相当于在索引上做运算,会让索引失效。mobile是字符类型,使用了数字,应该使用字符串匹配,否则MySQL会用到隐式替换,导致索引失效
select * from _user where mobile=12345678901
desc 和asc混用时会导致索引失效
索引的优点
减少了服务器扫描的行数
将随机io变成顺序io
数据结构
B+ tree
数据存在叶子节点,其他节点存指针
与B tree的比较
每个节点都存指针和数据,磁盘io是一样大小的单次查询情况下,B+ tree能够查询更多的节点
与红黑树比较
查询次数更少,红黑树是二叉树,每一层级只有两个节点,会导致深度会非常深,每次的层级跳转都是一次io操作,所以磁盘io会增加
联合索引
之所以最左匹配就是因为这个数据结构,联合索引A,B,C 需要先找到A 在找B在找C
undefined
分库分表
水平切分
按行拆分。拆分成多个相同的表,拆分出的每个表,结构是一样的
垂直切分
按列拆分。拆分成多个不同的表,每个表拥有的列是不一致的,通过唯一id关联
Sharding 策略
hash key 对表数量取模
范围,时间范围或者id范围
热点key问题
映射表
主从复制
步骤
Binlog线程
将主服务器数据写入二进制日志
I/O线程
从主服务器读取二进制日志,写入从服务器中继日志中(relay log)
Sql线程
读取中继日志(relay log)并重放sql语句
模式
stament
基于语句复制,记录每一条修改sql语句和每一行变化commit之后触发,所以可能导致主从不一致(两个事务事务1,2,事务2 后执行先commit)从库先收到事务2的语句
row
基于修改的行复制模式仅记录那条数据被修改了,被修改成什么样
mixed
混合模式,一般使用stament,对于可能导致主从不一致的转换成row模式
读写分离
主服务器处理写操作及实时性要求高的读操作,从服务处理读操作
锁
表锁
MyISAM 只支持表锁
行锁/记录锁
基于索引,锁定一个记录上的索引
间隙锁
RR级别下,MVCC + 间隙锁 解决幻读问题
范围查询时,对这个范围加锁 比如说 a>100 会对大于100的索引加锁,也会对大于100的间隙加锁
事务
特性
Automic
Constant
isolation
durability
隔离级别
Read Uncommitted
脏读,不可重复读,幻读
Read Committed
不可重复读,幻读
为什么应用选择rc级别不选择rr
1.rr存在间隙锁,rc不存在,rc模式下死锁几率小于rr2.rr模式下未命中索引会锁表,rc模式下只锁行
Repeatable Read
幻读
间隙锁 + mvcc 解决
为什么mysql 默认是rr级别
mysql在5.0以前主从之前只有stamemt模式,可能导致主从不一致,所以设置为rrrr 模式下引入间隙锁,两个事务1,2 事务1 修改数据时会锁住间隙,事务2执行插入会阻塞
Serializable
mvcc
多版本并发控制,主要依赖下面三个实现
数据库记录的3个隐藏字段
最近修改的事务id
回滚指针,指向当前记录的上一个版本
隐藏主键,如果表没有设置主键,innodb会自动生成一个
undolog
操作之前将当前版本数据记录下来,比如update record 时,会将当前值copy到undolog中更新数据,然后将隐藏字段的事务id修改为当前事务id将回滚指针指向undolog中的记录回滚时,按照指针找到旧的记录更新回来
readView
某个事务执行快照读时生成数据库系统当前的一个快照,记录当前活着的事务id如果隐藏列的事务id<活跃事务列表中最小的id 那这条数据对当前事务可见如果隐藏列的事务id > 活跃事务列表中最大的id,说明该条数据在readView生成之后才产生的,该数据对于当前事务来说不可见如果隐藏列的事务id在两者之间,则判断id是否在事务id活跃列表中如果在说明readView 生成时,当前事务时活跃的还未commit这条数据对当前事务不可见,如果不在列表中则说明此事务在readView生成的时候已经提交了,这条数据对当前事务可见
RR级别下,同一个事务中第一个快照读才会创建readView,之后的快照读都是同一个
RC 级别下,每个快照读都能生成并获取最新的readView,所以rc才能看到别的事务提交
查询过程
基础组件
buffer pool
缓冲池:每次请求会先从缓冲池中查询,缓冲池中没有,再去磁盘查找,放到缓冲池中
undo log
记录数据被修改前的样子
redo log
记录数据修改后的样子,mysql持久化的主力
bin log
记录整个操作过程
statment 基于sql语句的复制
row 基于行的复制
mixed (混合模式)两者都有
执行过程
执行器根据执行计划查询数据,线虫buffer pool中获取数据,如果没有就会去数据库中查询,如果查询到了就将其放到缓存池中
在数据被缓存到缓存池的同时,会写入 undo log 日志文件
更新的动作是在 BufferPool 中完成的,同时会将更新后的数据添加到 redo log buffer 中
在数据被缓存到缓存池的同时,会写入 undo log 日志文件
完成以后就可以提交事务
将redo log buffer 数据刷到磁盘
每次commit 刷盘
commit 时刷到os cache
每秒
同时将本次操作记录写入到 bin log文件中
为了保证数据一致性,采用两段式提交
undefined
同时将 bin log 文件名字和更新内容在 bin log 中的位置记录到redo log中同时在 redo log 最后添加 commit 标记
undefined
三大特性
自适应hash
当某个索引被使用的非常频繁,会在B+ tree上再创建一个hash索引让原本的索引具有hash索引的一些优点,比如快速查找
insert buffer
把普通索引(也就是辅助索引,并且不是唯一的)上的DML操作从随机io变成顺序io,从而提高io效率。先判断插入的普通索引页是否在缓冲池中,如果在直接插入,如果不在则放入change buffer,然后进行change buffer 和普通索引的合并操作,可以将多个操作合并成一个,提高普通索引插入性能
double write
把page写入file之前现将数据写入doublewritebuffer 中,之后将数据写入共享表空间之后写入数据文件如果在写入page 过程中崩溃可以通过doublewritebuffer 恢复数据,保证写入的安全性,防止宕机innodb发生数据页部分写的问题