MySQL逻辑架构
- 最上层服务: 连接处理,授权认证,安全等
- 第二层架构:包含了大多数的核心服务功能,包括:查询解析、分析、优化、缓存、内置函数,所有跨存储引擎的功能都在这一层实现,比如:存储过程、触发器、视图等
- 第三层架构:存储引擎,负责MySQL的数据存储和提取
锁
- 读写锁
- 共享锁/读锁
- 排它锁/写锁: 优先级高于读锁,一个写请求可能会被插在读锁队列前面
- 锁粒度
- 表锁:alter table 之类语句会使用表锁
- 行级锁
事务
隔离级别
- READ UNCOMMITTED 未提交读,事务中的未提交修改对其他事务可见,容易脏读,一般不用
- READ COMMITTED 提交读/不可重复读
- REPEATABLE READ 可重复读(MySQL默认事务隔离级别),引起幻读(当某个事务在读取范围内数据时,另一事务在范围内插入了新数据,某事务再次读取时,会产生幻行),MVCC解决了幻读的问题
- SERIALIZABLE 可串行化 ,最高的隔离级别,
多版本并发控制 MVCC
- MVCC只存在于可重复读、提交读两个隔离级别下
- 乐观并发控制、悲观并发控制
- MVCC是通过在每行记录后面保存两个列来实现的(行的创建时间系统版本号,行的过期/删除时间系统版本号),每开始一个新的事务,系统版本号就会递增,事务的版本号就是该事务开始时刻的系统版本号。
- 以InnoDB为例:
SELECT: 只查找版本号小于等于当前事务的数据行;行的删除版本要么未定义,要么大于当前事务版本号。
INSERT:为新插入行保存当前系统版本号为行版本号。
DELETE:为删除行保存当前系统版本号为行删除标识。
UPDATE:为新插入行保存当前系统版本号为行版本号,同时保存当前系统版本号为原来行的行删除标识。
还有啥
- 加快alter table 操作速度
- 常见的alter方法都是新建空表,从旧表中查出数据插入新表,然后废除旧表
- 其实并不是所有的alter操作都会引起表重建。
- 列的默认值存在表的.frm文件中,可以直接修改这个文件,这个语句会直接修改.frm文件而不涉及表数据
# 快速修改列默认值方法:
alter table film alter column end_time set default 5;
- 修改表默认编码方式
不推荐,只对新的字段生效,老的字段不会做改动
ALTER TABLE tb1 DEFAULT CHARACTER SET=utf8mb4 COLLATE utf8mb4_general_ci;
不推荐,只单独修改表里面某个字段的字符集类型不推荐:
ALTER TABLE tb1 change c c varchar(50) CHARACTER SET utf8mb4 not null default 'only for test' ;
推荐:这种写法老的字段也修改成utf8mb4:
ALTER TABLE tb1 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
- 修改注释
修改注释实际只修改.frm文件,不会改动ibd文件的,操作执行的很快。
alter table tb_name modify `column_name` default null comment '编号***'
alter table tb_name comment '用户表'
- 分页优化
常见的分页写法
select * from students limit 10000,20;
# 这样会将查出的10000行丢弃掉
优化:
可以取前一页的最大行数的id,然后根据这个id来限制下一页的起点。
例如:上一页最大的id是87654321。sql可以采用如下的写法:
select id,name from students where id> 87654321 limit 20
- MYSQL会在索引中储存null值,Oracle不会
- MySQL限制了每个关联操作最多只能有61张表,如果希望查询快且并发性好,单个查询最好在12个表以内做关联
- 缓存表对优化搜索很有效,对于缓存表,可以使用不同的存储引擎,比如MyISAM,会得到更小的索引占用空间,还可以全文搜索。
索引
一般我们说的索引大多数指的是B-Tree 索引,B-Tree 索引意味着所有的值都是按照顺序存储的,且每一个叶子页到根的距离相同,它之所以快,是因为搜索是从索引的根节点开始搜索, 而在根节点的槽中存放了指向子节点的指针。
- 此处有一张表
索引为 name, job_number, hired_time, 请暂时忽略索引的合理性,仅仅作为联合索引的讲述
CREATE TABLE employe (
name varchar(20) not null,
job_number int not null,
gender enum('m', 'f') not null,
hired_time date not null,
key(name, job_number, hired_time)
)
B-Tree 适合的索引查找类型:
- 全值匹配
比如: 搜索姓名Ann,工号为123456,入职时间为2018-11-11的员工 - 键值范围查询(由于索引列是顺序组织起来的,所以特别适合范围查找)
比如:搜索姓在Anna和David之间的员工,此时只使用了索引的第一列name - 键前缀查找(只适用于左前缀的查找)
比如:搜索姓名为Ann的员工或搜索姓名以A开头的员工 - 全值匹配+范围匹配
比如:查询姓名为Ann,工号大于12345的员工
关于B-Tree的限制
- 如果不是按照索引列的最前缀开始查找,则无法使用索引
比如:查找名字以a结尾的员工 - 不能跳过索引中的列
比如:搜索名字为Ann, 入职时间为2018-01-01至今的员工,跳过了工号这一列,则索引实际只会使用第一列name或者hired_time,这个就看MYSQL内部的优化选择了 - 如果查询中涉及到某个列的范围查询,那剩余右边的列都无法使用索引优化查找
比如:搜索姓名为Ann,且工号在A12至C123之间的,入职时间为2018-11-01的员工,此处工号为范围查询,所以入职时间这一类无法使用索引查询
其他
- 索引必须是独立的列,不能是表达式/函数等
- 前缀索引能使索引更小、更快,缺点是不能做 order by 和 group by
- 当不需要考虑排序和分组时,选择性高的列在前面是很好的
- 覆盖索引:一个查询的字段全是索引
- MySQL不能在索引中执行like操作