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

4GB内存限制下处理10亿个distinct id的最大ornum行提取方案咨询

4GB内存限制下处理10亿个distinct id的最大ornum行提取方案咨询

嗨,这个问题我太有发言权了!碰到10亿个唯一ID还只有4GB内存,确实不能用常规的内存密集型方法,得换磁盘友好的思路。先把咱们的问题背景再理一遍:

现有一张source表,结构如下:

id: LONG
name: STRING
ornum: LONG

我们的目标是生成target表,要为source里的每个唯一id,提取对应ornum最大的那一行数据。

之前用的SQL是:

CREATE OR REPLACE TABLE target AS SELECT DISTINCT ON(id) * FROM test ORDER BY ornum DESC;

这个写法在唯一ID数量不多的时候完全没问题,但如果碰到10亿级的唯一ID,4GB内存根本扛不住——毕竟要在内存里维护所有ID的状态,直接就爆内存了。

下面给你两个靠谱的、内存友好的解决方案:

方案1:基于外部排序的顺序去重(最省心,适用于支持窗口函数的数据库)

这个思路的核心是让数据库用磁盘做外部排序,而非全量加载到内存,然后顺序处理:

  1. 先对原表按id排序,同一个ID的行会被排在一起,并且每个ID组里ornum最大的行排在最前面。数据库会自动用临时磁盘文件做外部排序,不用占满内存:
    CREATE TEMP TABLE sorted_source AS
    SELECT * FROM source ORDER BY id, ornum DESC;
    
  2. 接着顺序扫描排序后的表,用窗口函数只保留每个ID的第一行(也就是ornum最大的行)。这一步不需要把所有ID都加载到内存,只需要维护当前正在处理的ID的状态,内存占用极低:
    CREATE OR REPLACE TABLE target AS
    SELECT * FROM sorted_source
    QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY ornum DESC) = 1;
    
    如果你的数据库不支持QUALIFY,可以用子查询替代:
    CREATE OR REPLACE TABLE target AS
    SELECT id, name, ornum FROM (
        SELECT *,
               ROW_NUMBER() OVER (PARTITION BY id ORDER BY ornum DESC) AS rn
        FROM sorted_source
    ) t WHERE rn = 1;
    

方案2:哈希分片拆分处理(通用型,适合所有数据库/引擎)

如果你的数据库对大表排序支持不太好,或者你想更精细控制内存占用,可以把大表拆成小分片处理:

  1. 按id的哈希值取模,把source表拆成N个小的临时表(分片)。比如分成1000个分片,每个分片大概有1000万左右的唯一ID,4GB内存完全能hold住:
    -- 示例:生成第0个分片
    CREATE TEMP TABLE source_shard_0 AS 
    SELECT * FROM source WHERE MOD(ABS(id::BIGINT), 1000) = 0;
    -- 重复这个逻辑,生成source_shard_1到source_shard_999
    
  2. 对每个分片单独执行原有的DISTINCT ON或者窗口函数逻辑,提取每个分片内的最大ornum行:
    -- 处理第0个分片
    CREATE TEMP TABLE target_shard_0 AS 
    SELECT DISTINCT ON(id) * FROM source_shard_0 ORDER BY id, ornum DESC;
    -- 重复处理所有分片
    
  3. 最后把所有分片的结果合并成最终的target表:
    CREATE OR REPLACE TABLE target AS
    SELECT * FROM target_shard_0
    UNION ALL SELECT * FROM target_shard_1
    -- 依次添加所有分片的查询
    UNION ALL SELECT * FROM target_shard_999;
    
    这个思路是把大问题拆成小问题,每个分片的内存占用都控制在4GB以内,完全不会爆内存。

额外小提示

  • 不管用哪个方案,都要避免让数据库在内存里做全量的分组聚合,一定要依赖外部排序或者分片拆分,这样内存占用只和单组/单分片的大小有关,和总ID数无关。
  • 如果是用Spark、Flink这类大数据引擎,直接用groupByKey然后取最大值就行,引擎会自动帮你做分片和内存管理,只要把executor内存配置在4GB以内就好。

备注:内容来源于stack exchange,提问作者pseudo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:19:35