批量更新数据首先要分页查询出来,那么有一个问题,如何去查?
能想到的最简单的方式,sql是这样的:
#先查出总数,分页
select count(*) from t where status = 2;
#过程如下
select id,name from t where status = 2 order by id limit 0, 100;
select id,name from t where status = 2 order by id limit 100, 100;
使用上面的语句,
首先就是巨慢,因为是查全量然后分页的。
其次,两次分页查询之间没有关联,如果有某些数据的状态,从status=1到了status=2,那么会导致一个问题:
由于页数已经确定(count不变),实际count + n了,那么本来在最后一页的数据,可能查不到了。
最好是这样:
每次查询都把上一批查询的数据的最大id作为查询条件带入,初始设置maxId(查出最早的id,不能用0,否则第一次就会扫描整个主键索引树), 每次分页查询后更新maxId,这样解决了上面的问题1和问题2,如下:
select id,name from t where id >= maxId and status = 2 order by id limit 100;
不过这样会有一个问题3:如果业务比较活跃,这张表一直有新数据插入,那么岂不是永远停不下来?
问题3这样的情况,数据页大概率在内存中,那么insert语句只写写到当前数据页中,不用进入change buffer,会写redo log,然后直接把内存中的数据返回,所以是有可能数据一直停不下来的(个人臆想了)。
后续:发现用maxId的方式,同样不太现实,如果id >= maxId 的数据多了,又回到了开始没有maxId的状态了,再次成为了慢查询语句,
解决方案是 再加一个 id <= maxId + 100000, 控制住扫表的行数,果然耗时降了