【问题标题】:Generate table with random values from other tables in PostgreSQL使用 PostgreSQL 中其他表的随机值生成表
【发布时间】:2020-09-17 20:04:29
【问题描述】:

以下代码使用 uuid_generate_v4() 为 Id 列生成 100000 行随机值。但是,嵌套选择始终选择同一行,因此所有插入的行对于这些列具有相同的值。目标是创建一个包含 100k 行的表,其中随机值取自其他样本表。每个示例表只有两列(Id 和从中获取值的列)。如何存档?

insert into "Tag" (
    "Id", "Time", "Account", "Name", "Value", "RollUpTableId"
)
select
    uuid_generate_v4(),
    current_timestamp,
    (select "Account" from "AccountSamples" OFFSET floor(random()*358) LIMIT 1),
    (select "Name" from "TagNameSamples" OFFSET floor(random()*19) LIMIT 1),
    (select "Value" from "TagValueSamples" OFFSET floor(random()*26) LIMIT 1),
    uuid_generate_v4()
from generate_series(1, 100000);

我也试过 从“AccountSamples”中选择“Account”,其中“Id” = (trunc(random() * 358)::integer)

【问题讨论】:

    标签: sql postgresql random subquery window-functions


    【解决方案1】:

    很可能,Postgres 正在优化子查询,并且不会为每一行重新执行它们。

    我建议在子查询中随机枚举,然后加入:

    select uuid_generate_v4(), a."Account", tns."Name", tvs."Value"
    from (
        select "Account", row_number() over(order by random()) rn from "AccountSamples"
    ) a
    inner join (
        select "Name",    row_number() over(order by random()) rn from "TagNameSamples"
    ) tns on tns.rn = a.rn
    inner join (
        select "Value",   row_number() over(order by random()) rn from "TagValueSamples"
    ) tvs on tvs.rn = a.rn
    where a.rn <= 10
    

    这与原始查询中的逻辑不完全相同,因为给定的行可能只能被选择一次 - 但我认为这是一个合理的近似值。

    如果您的某些表可能超过 10 行,那么 generate_series()left joins 更安全:

    select uuid_generate_v4(), a."Account", tns."Name", tvs."Value"
    from generate_series(1, 10) x(rn)
    left join (
        select "Account", row_number() over(order by random()) rn from "AccountSamples"
    ) a on a.rn = x.rn
    left join (
        select "Name",    row_number() over(order by random()) rn from "TagNameSamples"
    ) tns on tns.rn = x.rn
    left join (
        select "Value",   row_number() over(order by random()) rn from "TagValueSamples"
    ) tvs on tvs.rn = x.rn
    

    【讨论】:

    • 第一个选项最多只能创建 19 行。第二,修改 generate_series(1, 1000) 中的数字创建了所需的数量,但大部分都是空值,但是这里和那里都有一些值。
    • 这里是生成的示例i.imgur.com/UiYYV1k.png
    • @user33276346:看起来您在原始表中有 null 值。您可能希望在子查询中使用 where 子句将它们过滤掉。
    • 任何表中都没有空值。它们有 358、19 和 26 个值,已验证。不过,我不会将这些数字放在您提供的第二个查询中吗?
    • 对了,x(rn) 在那里做什么?
    【解决方案2】:

    对于任何可能处理类似问题的人,我正在分享一个来自 Reddit 的 pehrs 的 answer,它可以解决问题。

    在您的第一个解决方案中,问题是子选择没有 有任何外部依赖,所以会优化为随机调用 只有一次。您可以通过添加外部依赖项来解决此问题。尝试 像这样:

    select uuid_generate_v4(),
           current_timestamp,
           (select "Account" from "AccountSamples" WHERE gen=gen OFFSET floor(random()*358) LIMIT 1),
           (select "Name" from "TagNameSamples" WHERE gen=gen OFFSET floor(random()*19) LIMIT 1),
           (select "Value" from "TagValueSamples" WHERE gen=gen OFFSET floor(random()*26) LIMIT 1 ),
           uuid_generate_v4()
      from generate_series(1, 100000) gen;
    

    顺便说一下,典型的从表中随机挑选的方法 必须预先计算表格的大小就像

    SELECT foo FROM bar ORDER BY random() LIMIT 1
    

    它的性能并不过分,但它简单易懂。

    【讨论】:

      猜你喜欢
      • 2015-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多