You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从千万级数据表按uid分组取每组最后2条art_id记录(限200用户/请求)

解决方案

针对你这个1900万行的大表需求——分批处理200个用户、每个用户取最后2条文章记录、结果按uid排序,我整理了一套高效的实现方案,兼顾性能和业务逻辑:

核心SQL(单批处理200用户)

先看单批处理的核心逻辑,用窗口函数给每个用户的记录编号,确保拿到最新的2条,同时限制处理范围:

WITH user_batch AS (
    -- 筛选本次要处理的200个用户,可按uid分段避免重复处理
    SELECT DISTINCT uid
    FROM your_table_name
    -- 这里可以加WHERE uid > [上次处理的最大uid]来分页
    ORDER BY uid
    LIMIT 200
)
SELECT t.id, t.uid, t.art_id
FROM (
    SELECT 
        id, uid, art_id,
        -- 按uid分组,组内按id降序编号,rn=1是最新记录
        ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id DESC) AS rn
    FROM your_table_name
    WHERE uid IN (SELECT uid FROM user_batch)
) t
WHERE t.rn <= 2
ORDER BY t.uid, t.id DESC;

关键细节解释

  • 窗口函数ROW_NUMBER():这是实现“每个用户取N条”的标准写法,按uid分组后,用id DESC确保我们拿到的是最新插入的2条记录(如果你的“最后”是指原始插入顺序的末尾,把DESC改成ASC即可)。
  • 分批处理逻辑:通过user_batch这个CTE先锁定200个用户,避免一次性扫描全表,降低数据库负载。如果要迭代处理所有用户,只需要在user_batch里加WHERE uid > [上次处理的最大uid],逐步推进即可。
  • 排序要求:最终结果按uid排序,组内按id降序排列,完全符合你的需求。

大表性能优化必备

1900万行的数据量,必须靠索引提速,否则查询会慢到无法接受。创建这个复合索引:

CREATE INDEX idx_uid_id_desc ON your_table_name (uid, id DESC);

这个索引能让数据库直接定位每个用户的记录,并且已经按id降序排好,窗口函数不需要额外排序,执行效率会提升几个数量级。

用你的示例数据验证

假设你的表名为user_articles,去掉分批限制跑一遍核心逻辑:

SELECT t.id, t.uid, t.art_id
FROM (
    SELECT 
        id, uid, art_id,
        ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id DESC) AS rn
    FROM user_articles
) t
WHERE t.rn <= 2
ORDER BY t.uid, t.id DESC;

得到的结果是:

iduidart_id
51016
31013
71155
61136
81368

这正是每个用户最新的2条记录,如果你需要的是按原始顺序的最后2条(比如uid10取id1、5),把窗口函数里的ORDER BY id DESC改成ORDER BY id ASC就行。

迭代处理全量用户

你可以用脚本(Python/Shell/数据库存储过程)来自动分批处理:

  • 初始化last_processed_uid = 0
  • 循环执行:
    1. 运行带WHERE uid > last_processed_uid的SQL
    2. 处理返回的结果(导出/写入目标表)
    3. 更新last_processed_uid为本次处理的最大uid
    4. 直到查询返回的用户数不足200,结束循环

这样就能高效处理完1900万行数据,不会对数据库造成太大压力。


内容的提问来源于stack exchange,提问作者Tutti Frutti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:46:55