日常在项目中通过offset及limit实现分页功能,limit可以限制每次查询的时候只查询几条数据,今天无意中发现join查询时,limit查询数据条数出现问题。
applys = (
NewApply.query.join(ApproveUser)
.filter(
*filters
)
.order_by(NewApply.create_time.desc()).offset((page_num - 1) * page_size).limit(page_size).all()
)
正常情况下,上述代码查询出来的条数,应为limit中的page_size,但当我输入pagesize=20时,却查询出了以下结果:
此时并不知道是什么原因会出现这种情况,无奈只能调出sql看一下
上图为使用原生sql查询,确实查出了20条数据,但可以看到有条重复数据,这样之前的问题就找到原因了,在sqlalchemy中limit20条时,确实查询出了20条数据,只不过因为join查询,会产生重复数据,sqlakchemy应该是筛除了重复条数,导致查询出的结果不是limit的数值。
解决办法:
找到原因,那解决起来也很简单,我这边有两种解决办法:
1.通过group_by主表的主健,来提前筛除重复数据
applys = (
NewApply.query.join(ApproveUser)
.filter(
*filters
)
.order_by(NewApply.create_time.desc()).group_by(NewApply.object_id).offset((page_num - 1) * page_size).limit(page_size).all()
)
注意要在limit之前group_by
这个方法的缺点在于条数庞大时,gruop_by会直接崩溃中断,之前遇到过万条级别的崩溃,一般情况下是可以放心用的。
2.在查询结束时进行切片已实现分页目的
applys = (
NewApply.query.join(ApproveUser)
.filter(
*filters
)
.order_by(NewApply.create_time.desc())
.all()[(page_num - 1) * page_size:page_num*page_size]
)
之前自己是比较排斥这种用法的,觉得先查询再切片会影响性能,但经过测试,性能是和offset和limit相差无几的。