Gem 使用 Kaminari 分页时,遇到使用 distinct 的语句,分页会不准确

wfwdex · 2017年05月31日 · 最后由 zj0713001 回复于 2017年06月08日 · 2370 次阅读

使用 kaminari 对去重的语句进行分页时,生成的分页语句有问题:

logs = OperationLog.select(:user_id).where(interface_id: params[:interface_id]).page(param_page).per(param_limit).distinct.includes(:user)

生成的语句

-- 分页语句
SELECT  DISTINCT `operation_logs`.`user_id` FROM `operation_logs` WHERE `operation_logs`.`interface_id` = 1 LIMIT 25 OFFSET 0
-- 查询关联用户
SELECT `users`.* FROM `users` WHERE `users`.`id` IN (150, 123, 175, 126, 133, 124)
-- 获取总记录数
SELECT DISTINCT COUNT(DISTINCT `operation_logs`.`id`) FROM `operation_logs` WHERE `operation_logs`.`interface_id` = 1

事实上总记录数并没有按 DISTINCT 指定的字段去重,导致总记录数是未去重的数量,

查了 kaminari 项目 README.md 和 google,都没找到解决方法,目前使用的是 Kaminari.paginate_array,对总结果分页,这样显然是不对的,记录数多了之后,性能有很大问题。

请问这个问题怎么解决?

distinct 放在 page 前面调用的话呢?

ywjno 回复

谢谢回复,试了一下,生成的语句是一样的,没有变化。

换了个思路,使用以下方式解决....

logs = OperationLog.select(:user_id).where(interface_id: params[:interface_id]).page(param_page).per(param_limit).group(:user_id).includes(:user)

你这样会丢 OperationLog 的,每个 user 未必只有一个 log,group 是聚合~ 所以你的需求是什么~

OperationLog.joins(:user).select(:user_id).distinct.where(interface_id: params[:interface_id]).page(1).per(10) 

这样试试呢?

zj0713001 回复

我的需求是让记录按我要求的字段去重后可以正常分页。现在看来不能用 distinct,还是用 group 比较好。

rd084c 回复

谢谢回复,我的项目里 users 和 logs 是在不同的数据库里,所以不能用 join

wfwdex 回复

我的问题是~ group 并不是去重,会丢数据的~ 比方说 log 有 create_at 聚合以后只能显示一组相同字段数据里的某一个值了

zj0713001 回复

谢谢回复,没关系,我的需求里在分组时,只需要算分组后每组数据有多少条,或者某个数值字段的总合,所以分组正合适的。

是我之前把概念搞错了,所以错用了 distinct。

wfwdex 回复

那这个需求就恰好是 group 的使用场景~

需要 登录 后方可回复, 如果你还没有账号请 注册新账号