Skip to content

Laravel实操记录之chunk

chunk在计算机行业通常表示数据块。数据库查询下也有一个chunk方法,依据函数式编程思想设计。第一个参数是chunk大小,第二个参数是一个callable。

使用方法如下:

它的实现方式其实不高深但是用于批量传输数据的时候非常实用。代码实现在 Illuminate\Database\Concerns\BuildsQueries (Laravel 5.4)。copy如下:

可以看到其实就是一个分页查询。因此它也具备分页查询的缺点:在超长列表下查询性能差。比如100w的列表,查询到后面会出现Limit 990000, 100这样的分页查询,对于超大的偏移量,MySQL的处理是从头扫描!!!因此,分页越往后单个查询耗时越多。

上图是一个数据库QPS(每秒查询数)记录,15:00~17:00有三段下坡的曲线就是执行上面代码产生的(三次运行,使用不同limit,所以基数不同),充分阐释了offset带来的性能问题。每一次执行之初具有极快的返回时间,所以每秒可以发送更多的请求。随着offset增大,每次查询耗时越来越多,导致每秒可返回的查询数不断减少。

这种情况可以结合实际情况对查询条件进行优化,因为上面查询是主键扫描,所以可以用主键做分段条件,类似上面那个查询我是这样做的:

因为这个查询是根据id升序排序查询,所以将超长列表根据id再分区间。避免过大的offset。而条件中的id因为是主键,所以可以利用索引快速定位。因此可以一定程度上提高效率。上图17:00之后的统计曲线就是优化之后的代码产生的,可以看到已经没有了衰减的趋势(个别位置凹下去是因为跑完了$start~$end的所有数据,手动重启的间隙)。

总结一下,这种批量处理数据避免过大的offset是性能提升的关键,其次在内存、写入等条件允许的情况下提高limit也有一定好处。其实上面例子中区间长度如果与chunk相等是最优效果。可是这样的话有什么好chunk呢

分享到:
Published in程序猿的东西

Be First to Comment

发表评论