读书笔记-高性能MySQL中获取的额外干货

MySQL逻辑架构

  • 最上层服务: 连接处理,授权认证,安全等
  • 第二层架构:包含了大多数的核心服务功能,包括:查询解析、分析、优化、缓存、内置函数,所有跨存储引擎的功能都在这一层实现,比如:存储过程、触发器、视图等
  • 第三层架构:存储引擎,负责MySQL的数据存储和提取

  1. 读写锁
  • 共享锁/读锁
  • 排它锁/写锁: 优先级高于读锁,一个写请求可能会被插在读锁队列前面
  1. 锁粒度
  • 表锁:alter table 之类语句会使用表锁
  • 行级锁

事务

隔离级别

  • READ UNCOMMITTED 未提交读,事务中的未提交修改对其他事务可见,容易脏读,一般不用
  • READ COMMITTED 提交读/不可重复读
  • REPEATABLE READ 可重复读(MySQL默认事务隔离级别),引起幻读(当某个事务在读取范围内数据时,另一事务在范围内插入了新数据,某事务再次读取时,会产生幻行),MVCC解决了幻读的问题
  • SERIALIZABLE 可串行化 ,最高的隔离级别,

多版本并发控制 MVCC

  • MVCC只存在于可重复读、提交读两个隔离级别下
  • 乐观并发控制、悲观并发控制
  • MVCC是通过在每行记录后面保存两个列来实现的(行的创建时间系统版本号,行的过期/删除时间系统版本号),每开始一个新的事务,系统版本号就会递增,事务的版本号就是该事务开始时刻的系统版本号。
  • 以InnoDB为例:

    SELECT: 只查找版本号小于等于当前事务的数据行;行的删除版本要么未定义,要么大于当前事务版本号。

    INSERT:为新插入行保存当前系统版本号为行版本号。

    DELETE:为删除行保存当前系统版本号为行删除标识。

    UPDATE:为新插入行保存当前系统版本号为行版本号,同时保存当前系统版本号为原来行的行删除标识。

还有啥

  1. 加快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
  1. MYSQL会在索引中储存null值,Oracle不会
  2. MySQL限制了每个关联操作最多只能有61张表,如果希望查询快且并发性好,单个查询最好在12个表以内做关联
  3. 缓存表对优化搜索很有效,对于缓存表,可以使用不同的存储引擎,比如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 适合的索引查找类型:

  1. 全值匹配

    比如: 搜索姓名Ann,工号为123456,入职时间为2018-11-11的员工
  2. 键值范围查询(由于索引列是顺序组织起来的,所以特别适合范围查找)

    比如:搜索姓在Anna和David之间的员工,此时只使用了索引的第一列name
  3. 键前缀查找(只适用于左前缀的查找)

    比如:搜索姓名为Ann的员工或搜索姓名以A开头的员工
  4. 全值匹配+范围匹配

    比如:查询姓名为Ann,工号大于12345的员工

关于B-Tree的限制

  1. 如果不是按照索引列的最前缀开始查找,则无法使用索引

    比如:查找名字以a结尾的员工
  2. 不能跳过索引中的列

    比如:搜索名字为Ann, 入职时间为2018-01-01至今的员工,跳过了工号这一列,则索引实际只会使用第一列name或者hired_time,这个就看MYSQL内部的优化选择了
  3. 如果查询中涉及到某个列的范围查询,那剩余右边的列都无法使用索引优化查找

    比如:搜索姓名为Ann,且工号在A12至C123之间的,入职时间为2018-11-01的员工,此处工号为范围查询,所以入职时间这一类无法使用索引查询

其他

  1. 索引必须是独立的列,不能是表达式/函数等
  2. 前缀索引能使索引更小、更快,缺点是不能做 order by 和 group by
  3. 当不需要考虑排序和分组时,选择性高的列在前面是很好的
  4. 覆盖索引:一个查询的字段全是索引
  5. MySQL不能在索引中执行like操作
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章