Postgres结合GORM实现基于ID的键集分页与Title去重查询
实现PostgreSQL中唯一Title的键集分页(GORM+原生SQL方案)
核心思路
- 保证Title唯一:如果表中未给
title加唯一约束,需通过分组聚合(取每个title对应的最小id)得到去重后的id-title集合;若已有唯一约束,可直接跳过此步。 - 键集分页实现:利用
id的唯一性与有序性,用WHERE id > 上一页最大id替代传统OFFSET,避免大偏移量导致的性能损耗,同时保证分页结果的稳定性(数据插入/删除时不会出现重复或遗漏)。
GORM实现方案
1. 定义数据结构
如果不需要映射完整表结构,可定义专用返回结构体:
type UniqueTitleItem struct { ID uint `gorm:"column:id"` Title string `gorm:"column:title"` }
2. 第一页查询
通过CTE(公共表表达式)先获取去重后的数据集,再分页:
var page1 []UniqueTitleItem err := db. With("unique_titles", db.Table("articles").Select("MIN(id) as id, title").Group("title")). Table("unique_titles"). Order("id ASC"). Limit(3). Scan(&page1).Error if err != nil { // 处理错误逻辑 } // 记录当前页最大ID,用于下一页查询 lastID := page1[len(page1)-1].ID
3. 后续页查询
基于上一页的最大id作为查询条件:
var page2 []UniqueTitleItem err := db. With("unique_titles", db.Table("articles").Select("MIN(id) as id, title").Group("title")). Table("unique_titles"). Where("id > ?", lastID). Order("id ASC"). Limit(3). Scan(&page2).Error
若表中
title已添加唯一约束,可简化为直接查询,无需CTE分组:// 第一页 var page1 []Article db.Select("id, title").Order("id ASC").Limit(3).Find(&page1) // 后续页 var page2 []Article db.Select("id, title").Where("id > ?", lastID).Order("id ASC").Limit(3).Find(&page2)
原生SQL方案
第一页SQL
WITH unique_titles AS ( SELECT MIN(id) AS id, title FROM articles GROUP BY title ) SELECT id, title FROM unique_titles ORDER BY id ASC LIMIT 3;
第二页SQL(假设上一页最大ID为4)
WITH unique_titles AS ( SELECT MIN(id) AS id, title FROM articles GROUP BY title ) SELECT id, title FROM unique_titles WHERE id > 4 ORDER BY id ASC LIMIT 3;
注意事项
- 确保
id字段有索引(主键默认带索引),否则键集分页的性能优势无法体现。 - 若需按
title排序后分页,需保证排序字段的唯一性(可结合id作为排序条件,如ORDER BY title ASC, id ASC),避免分页结果出现重复或遗漏。
内容的提问来源于stack exchange,提问作者Anni Benni
相关产品推荐
相关产品推荐

