10
0
0
MySQL 随手记:深分页改游标,锁的几个坑
数据库笔记碎片,一半是查出来的,一半是踩出来的。
深分页:LIMIT 1000000, 10 为什么慢
MySQL 不是「跳过前 100 万行」,是先扫出 100010 行,再把前 100 万行全丢掉——IO 和回表全白干。
-- 慢:深翻页
SELECT * FROM t WHERE type = 1 ORDER BY id LIMIT 1000000, 10;
-- 快:游标法(上一页最后一条的 id 当锚点)
SELECT * FROM t WHERE type = 1 AND id > #{lastId} ORDER BY id LIMIT 10;注意两点:
- 游标法必须有唯一递增列,没有就拿 (时间, id) 组合锚点
- 排序字段不止一个时,WHERE 里要把所有排序字段都带上条件,否则丢数据
- 代价:游标法不能跳页,只能上一页/下一页——分页器要按这个设计
锁的坑
- RR 隔离级别下才有间隙锁防幻读,RC 下不防——「可重复读」和「读已提交」的行为差异,做分布式锁/幂等时会撞上
- update where 非索引列 = 锁全表:线上事故就是一条
update t set x where status=1,status 没索引,直接把整表锁住几秒 - 8.0 查锁换到
performance_schema.data_locks,旧的information_schema.INNODB_LOCKS已废弃
其他零碎
count(*):InnoDB 会走最窄的二级索引,别再纠结 count(*) / count(1) / count(主键) 了,一样- 隐式转换吃索引:varchar 列拿数字比、字段套函数
where date(create_time)=…都会让索引失效 - 分页查询第二页起用不到覆盖索引时回表暴涨,深翻页优先上文的游标法