这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
从性能方面开始考虑 【业务代码已经保证不会写入重复数据的情况下】
查询过程
1. 普通索引 - 查找到满足条件的第一个记录后 - 需要查找下一个记录 - 直到碰到第一个不满足条件的记录
1. 唯一索引 - 索引定义的唯一性 - 查找到第一个满足条件的记录 - 停止继续检索
InnoDB的数据是按数据页为单位来读写的 - 需要一条记录时,不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存
普通索引 - 多做的那次“查找和判断下一条记录”的操作 - 只需要一次指针寻找和一次计算
更新过程
change buffer - 持久化数据【在内存中有拷贝,也会被写入磁盘】
需要更新一个数据页时 - 数据页在内存中 - 直接更新
- 数据页不在内存中 - 不影响数据一致性前提下 - 更新操作缓存在change buffer - 下次查询需要访问这个数据页时 - 数据页读入内存 - 执行change buffer 中与这个页有关的操作 - 保证数据逻辑的正确性
用的是buffer pool中的内存 - 不能无限大 - innodb_change_buffer_max_size 来动态设置 EG:50 - change buffer的大小最多只能占用buffer pool的50%
merge
1. change buffer中的操作应用到原数据页 【访问数据页时触发】
1. 系统后台线程定期merge
1. 数据库正常关闭【shutdown】
优点
1. 减少读磁盘 - 语句执行速度明显提升
1. 数据读入内存 - 占用buffer pool - ∴ 避免占用内存,提高内存利用率
什么条件可以使用change buffer?
- 唯一索引 - 先判断该操作是否违反唯一性约束 必须将数据页读入内存才能判断 - 无需使用change buffer ∴ 普通索引中使用change buffer
插入新记录(4, 400)的处理流程
-
该记录要更新的目标页在内存中 -
- 唯一索引 - 找到3和5的位置 - 判断到没有冲突 - 插入该值 - 语句执行结束
- 普通索引 - 找到3和5的位置 - 插入该值 - 语句执行结束
普通索引和唯一索引对更新语句性能影响的差别只是一个判断 - 耗费微小的CPU时间
-
该记录要更新的目标页不在内存中 -
- 唯一索引 - 将该记录所在数据页读入到内存 - 找到3和5的位置 【重复在内存中的操作】
- 普通索引 - 将更新记录在change buffer中,语句执行结束
数据从磁盘中读入内存涉及随机IO的访问 - 数据库成本最高的操作之一 change buffer减少了磁盘访问 - 更新性能的提升会很明显
change buffer使用场景
写多读少 - change buffer中记录的变更越多 - 收益越大 - 账单类、日志类系统 普通索引 + change buffer【尽量开大】=> 数据量大的表的更新优化 尽量选择普通索引, 如果所有更新后面马上伴随着有该记录的查询 - 关闭change buffer【反而增加了change buffer的维护代价】
首先要保证业务正确,业务正确性优先 - 如果碰上大量插入数据慢,内存命中率低的时候 - 多一条排查思路 + 一些“归档库”的场景【历史数据要保存在归档库中 - 此时归档数据已经确保没有唯一键冲突 - 普通索引提高归档效率】
change buffer和redo log
WAL提升性能的核心机制 - 尽量减少随机读写
写入
insert into t(id, k) values(id1, k1), (id2, k2); - k1所在数据页在内存中,k2所在数据页不在内存中
内存、redo log、数据表空间(t.ibd)、系统表空间(ibdata1)
- page1在内存中 - 直接更新内存
- page2不在内存 - 从内存的change buffer区域记录该条操作
- 将上述两个动作记入redo log中
执行该更新语句成本很低 - 写了两处内存,写了一处磁盘【两个操作合在一起写了一次磁盘】【顺序写】
读请求
select * from t where k in(k1, k2)
若语句发生在更新语句后不久 - 内存中的数据还在 - 此时两个读操作与系统表空间和redo log无关
- 读Page1时,直接从内存中返回 WAL技术后,如果读数据,是不是一定要读盘?一定要从redo log中把数据更新以后才可以返回? 不用 - 如上图状态 - 磁盘中还是之前的数据 - 但是直接从内存返回正确结果【此时内存中是最新值、redo log中记录的是最新操作,磁盘中还未刷新成最新值
- 读Page2时,把Page2读入内存,应用change buffer里面的操作日志,生成一个正确的版本并返回结果 - 需要读page2时,该数据页才会被读入内存
redo log节省随机写磁盘的IO消耗【转成顺序写】 change buffer节省随机读磁盘的IO消耗