基础篇

sql执行流程

  • 连接器:简历连接、管理连接、校验用户身份
  • 解析sql:此法语法分析,构建语法树
  • 执行sql
    • 预处理阶段:检查表或字段是否存在
    • 优化阶段:最小查询成本的执行计划
    • 执行阶段:按执行计划执行sql

EXPLAIN 详解

type

  • select_type
  • type(system > const > eq_ref > ref > range > index > all)
    • system、const 常量记录数
    • eg_ref 主键或唯一索引被连接
    • ref 普通索引,多个符合条件的记录行
    • range 范围查询
    • index 扫描全表索引,一般是某个二级索引
    • ALL 全表扫面
  • possible_keys 可能用到索引
  • key 实际索引
  • rows 读取行数
  • extra列
    • use index 覆盖索引
    • use where 使用where语句,字段未被索引覆盖
    • use index condition 查询的列不完全被索引覆盖
    • useing temporary 临时表要优化
    • useing filesort 外部排序不是索引排序,数据小内存,大磁盘

索引篇

索引失效

  • 左或左右模糊匹配
  • 对索引使用函数
  • 对索引进行表达式计算
  • 对索引使用隐形转换
  • 联合索引非最左匹配; index(a,b,c) where a=1 and c=3 索引截断,5.6版本后锁、索引下推减少回表次数
  • where 子句中的 or;where id=1 or age = 10 对 age 加索引 可以走 index merge 避免全表扫描

索引区别

  • exist 子查询使用索引
  • not exist 主子查询使用索引
  • in 与子查询一起,只能主查询使用索引
  • not in 不使用索引

事务篇

特性 ACID

持久性 redo log(重做日志)

原子性 undo log(回滚日志)

隔离性 mvcc(多并发版本控制)

一致性则通过持久性+原子性+隔离性来保证

并发引起事务问题?

同时多个事务的时候,可能出现脏读、不可重复读、幻读等问题

脏读,读到其他事务未提交的数据;。

不可重复读,前后读取的数据不一致;。

幻读,前后读取的记录数量不一致。

隔离级别

读未提交

读提交

可重复读(默认),很大程度上避免了幻读,开启事务后尽快执行 select…for update 当前读使用next-key lock避免

串行化,会对记录加上读写锁

锁篇

日志篇

内存篇

架构设计

缓存设计

缓存失效

过期时间设置不合理,大量key同时过期,导致数据库压力,可能雪崩

解决:错开各key过期时间及分批次刷新

缓存穿透

数据库不存在的记录

  1. 现在记录不存在,不表示一直不存在
  2. 可能存在大量值为空的垃圾记录(攻击居多)

解决方法:

  1. 布隆过滤器Bloom Filter,空间效率很高的随机数据结构,位数组很简洁标识一个集合,高效判断元素是否存在(比如黑名单,不存在的id加入)

缓存一致性

参看三种经典的缓存模式

热点数据

  • 极热点数据,可设置永不过期(或长时间不过期),定时刷新

数据迁移与同步

动态数据迁移

  1. 性服务线上sql脚本和es初始化
  2. 导出老服务全量数据(db和es),并记录时间点t1时刻
  3. 迁移全量数据(db和es)
  4. 新服务上线
  5. 老服务加入切流量功能后上线,切流量开关默认关闭
  6. 灰度发布
    1. 新服务以测试域名上线,与老服务同时运行
    2. 打开切流量开关,让部分用户流入到新服务,尽量选流量小时刻
    3. 新服务稳定后,全部切到新服务上,老服务下线,切流完成,记录t2时刻
  7. 增量数据迁移,查询全量数据t1时刻到t2时刻的,这段时间老服务新增或更新的数据库并迁移到新服务

静态数据迁移

数据变化小,一段时间不可用,直接导出迁移

一致性方案

强一致性

写入什么,读出来什么,体验好,实现对系统的影响大

弱一致性

写入后,不承诺可以读到写入的值,尽可能在某个时间级别(秒级别),数据达到一致

最终一致性

弱一致性的一个特例,系统保证在一定时间内,能够达到一个数据一致的状态。

三种经典的缓存模式

旁路缓存模式(Cache-Aside Pattern)

读流程
  1. 读的时候,先读缓存,命中缓存的话,直接返回数据。
  2. 缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。
写流程
  • 先更新数据库,再删除缓存。

Read-Through/Write-Through(读写穿透)

Read-Through
  1. 从缓存读取数据,读到直接返回
  2. 如果读取不到的话,从数据库加载,写入缓存后,再返回响应。

与Cache-Aside比,多了一层 Cache-Provider封装。

Write behind (异步缓存写入)

Write behindRead-Through/Write-Through有相似的地方,都是由 Cache Provider来负责缓存和数据库的读写。它两又有个很大的不同:Read/Write Through是同步更新缓存和数据的,Write Behind则是只更新缓存,不直接更新数据库,通过批量异步的方式来更新数据库。