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

PL/pgSQL按权重占比随机选取姓名生成测试样本数据方案咨询

PostgreSQL 加权随机生成姓名测试数据最优实现

核心优化思路

要满足100万级样本的生成效率,必须避免逐行循环查表的低效模式,改用批量集合操作:

  • 仅1次预计算名字/姓氏的权重区间,无需每次生成都重复查表
  • 一次性生成所有需要的随机值,批量匹配出对应姓名
  • 尽量减少PL/pgSQL循环次数,多用原生SQL执行批量操作

方案1:无需修改原有表结构(适合临时使用场景)

这个方案不需要改动现有表,直接通过CTE预计算累计权重,执行效率足够支撑100万条数据生成:

CREATE OR REPLACE FUNCTION create_sample_data(p_number_of_records INT)
RETURNS VOID AS $$
DECLARE
    v_records INT := coalesce(p_number_of_records, 0);
    v_full_name TEXT;
BEGIN
    IF v_records <= 0 THEN
        RETURN;
    END IF;

    -- 批量生成所有姓名后统一处理,避免循环内多次查表
    FOR v_full_name IN
        WITH 
        -- 预计算名字的权重区间
        first_name_intervals AS (
            SELECT 
                first_name,
                SUM(ratio) OVER (ORDER BY first_name) AS cum_upper,
                LAG(SUM(ratio) OVER (ORDER BY first_name), 1, 0) OVER (ORDER BY first_name) AS cum_lower
            FROM common_first_name
        ),
        -- 预计算姓氏的权重区间
        last_name_intervals AS (
            SELECT 
                last_name,
                SUM(ratio) OVER (ORDER BY last_name) AS cum_upper,
                LAG(SUM(ratio) OVER (ORDER BY last_name), 1, 0) OVER (ORDER BY last_name) AS cum_lower
            FROM common_last_name
        ),
        -- 生成指定数量的随机数对,每个对应一个姓名的随机权重
        random_seeds AS (
            SELECT 
                random() * 100 AS rnd_first,
                random() * 100 AS rnd_last
            FROM generate_series(1, v_records)
        )
        -- 匹配出符合权重分布的姓名
        SELECT f.first_name || ' ' || l.last_name AS full_name
        FROM random_seeds s
        JOIN first_name_intervals f ON s.rnd_first >= f.cum_lower AND s.rnd_first < f.cum_upper
        JOIN last_name_intervals l ON s.rnd_last >= l.cum_lower AND s.rnd_last < l.cum_upper
    LOOP
        -- 调用你已有的人员生成函数
        PERFORM create_person(v_full_name);
    END LOOP;
END
$$ LANGUAGE plpgsql VOLATILE;

方案2:修改表结构预存权重区间(适合频繁生成数据场景)

如果需要经常调用该函数,建议预存累计权重并加索引,进一步提升性能:

步骤1:新增累计权重字段并初始化

-- 名字表加字段
ALTER TABLE common_first_name ADD COLUMN cum_lower NUMERIC, ADD COLUMN cum_upper NUMERIC;
-- 初始化权重区间
WITH intervals AS (
    SELECT 
        first_name,
        SUM(ratio) OVER (ORDER BY first_name) AS cum_upper,
        LAG(SUM(ratio) OVER (ORDER BY first_name), 1, 0) OVER (ORDER BY first_name) AS cum_lower
    FROM common_first_name
)
UPDATE common_first_name f
SET cum_lower = i.cum_lower, cum_upper = i.cum_upper
FROM intervals i WHERE f.first_name = i.first_name;
-- 加索引加速匹配
CREATE INDEX idx_first_name_interval ON common_first_name(cum_lower, cum_upper);

-- 姓氏表同理执行相同操作
ALTER TABLE common_last_name ADD COLUMN cum_lower NUMERIC, ADD COLUMN cum_upper NUMERIC;
WITH intervals AS (
    SELECT 
        last_name,
        SUM(ratio) OVER (ORDER BY last_name) AS cum_upper,
        LAG(SUM(ratio) OVER (ORDER BY last_name), 1, 0) OVER (ORDER BY last_name) AS cum_lower
    FROM common_last_name
)
UPDATE common_last_name l
SET cum_lower = i.cum_lower, cum_upper = i.cum_upper
FROM intervals i WHERE l.last_name = i.last_name;
CREATE INDEX idx_last_name_interval ON common_last_name(cum_lower, cum_upper);

步骤2:优化后的函数(无需每次预计算区间)

CREATE OR REPLACE FUNCTION create_sample_data(p_number_of_records INT)
RETURNS VOID AS $$
DECLARE
    v_records INT := coalesce(p_number_of_records, 0);
    v_full_name TEXT;
BEGIN
    IF v_records <= 0 THEN
        RETURN;
    END IF;

    FOR v_full_name IN
        SELECT f.first_name || ' ' || l.last_name AS full_name
        FROM (
            SELECT random() * 100 AS rnd_first, random() * 100 AS rnd_last
            FROM generate_series(1, v_records)
        ) s
        JOIN common_first_name f ON s.rnd_first >= f.cum_lower AND s.rnd_first < f.cum_upper
        JOIN common_last_name l ON s.rnd_last >= l.cum_lower AND s.rnd_last < l.cum_upper
    LOOP
        PERFORM create_person(v_full_name);
    END LOOP;
END
$$ LANGUAGE plpgsql VOLATILE;

额外性能提升建议

如果你的create_person函数仅做插入操作,建议修改为支持批量输入的版本,直接将批量匹配出来的姓名集合一次性插入,完全去掉PL/pgSQL循环,100万条数据生成速度可提升至10秒以内。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:54:03