【问题标题】:unique random timestamp in postgresqlpostgresql中的唯一随机时间戳
【发布时间】:2014-03-09 10:00:24
【问题描述】:

我尝试了好几个小时来做​​到这一点。我需要创建 100.000 行,时间戳是主键。这就是为什么它必须是独一无二的。

我写了一些代码,它可以生成 100 个随机时间戳,但如果我尝试超过 100 个,例如 1000 或 10000,我就会出现错误,就像那样

错误:重复键值违反唯一约束“position_pkey” SQL状态:23505详细信息:键(“时间戳”)=(2014-03-09 04:03:16.843499) 已经存在。

我不知道如何创建 100.000 个唯一时间戳。

这是我的功能

CREATE OR REPLACE FUNCTION generate_random(count integer DEFAULT 1)
  RETURNS SETOF timestamp AS
$BODY$
    BEGIN
            RETURN QUERY SELECT distinct NOW()::timestamp + '10ms'::interval *RANDOM()*RANDOM()
FROM generate_series(0,count);

            --SELECT (NOW() - '10000000'::INTERVAL * ROUND(RANDOM() * RANDOM()))::timestamp
                    --     FROM GENERATE_SERIES(1, count);
        END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 1000;

这是 generate_random 函数,它随机生成双数。

CREATE OR REPLACE FUNCTION generate_random(c integer DEFAULT 1, min double precision DEFAULT 0.0, max double precision DEFAULT 1.0)
  RETURNS SETOF double precision AS
$BODY$
        BEGIN
            RETURN QUERY SELECT min + (max - min) * RANDOM()
                         FROM GENERATE_SERIES(1, c);
        END;
    $BODY$
  LANGUAGE plpgsql VOLATILE STRICT
  COST 100
  ROWS 1000;

我在查询中这样调用这个函数

INSERT INTO "mytable"(
            "timestamp", x, y, z)
    VALUES (generate_random(1000), generate_random(1000, 0, 50), generate_random(1000, 0, 50), generate_random(1000, 0, 50));

所以,我想创建 100.000 行,它们是唯一的时间戳和一些随机双数(无论是否唯一)

【问题讨论】:

    标签: sql postgresql random timestamp


    【解决方案1】:

    There's a function on the PostgreSQL wiki, pseudo_encrypt, that will produce pseudo-random values distributed across the 32-bit integer space.

    使用 feistel 密码从序列进行 1:1 映射的相同方法可用于时间戳。

    或者您可以使用非重复迭代伪随机数生成器。

    主要的是,如果将结果缩小到更小的空间,则必须小心,因为会出现冲突。

    【讨论】:

      【解决方案2】:

      保证唯一时间戳的唯一方法是在插入之间添加延迟。相反,您可以使用序列号

      create table mytable (
          s serial primary key,
          ts timestamp,
          x int,
          y int,
          z int
      );
      insert into mytable (ts, x, y, z) 
      select 
          clock_timestamp(),
          500 * RANDOM(),
          500 * RANDOM(),
          500 * RANDOM()
      from generate_series(1, 1000)
      ;
      

      【讨论】:

      • well distributed != random,但差异确实取决于 OP 的要求。
      • 谢谢你的回答,我会试试这段代码,但是postgresql的延迟呢?我用谷歌搜索并没有找到样本..我只是看到一些睡眠功能..它对 100.000 行有好处吗?
      • @Clodoaldo Neto,我使用了你的代码,看起来不错,但我想生成介于 -100 和 100 之间的双数。我不知道它不起作用。我写的是 100 而不是 500,它仍然会生成数字直到 500.. 很奇怪..?
      【解决方案3】:

      permuteseq 扩展名可以是 用于生成包含具有随机外观的唯一值的区间 分布。

      这是一个在其中生成 100000 唯一时间戳的示例 10000000(1000 万)个可能值,基于 将伪随机序列中的元素乘以10ms 间隔 添加到now()

      CREATE EXTENSION permuteseq;
      
      CREATE TABLE uniq_tstamp(t timestamp);
      
      INSERT INTO uniq_tstamp
       SELECT now()+range_encrypt_element(elt, 1, 10000000, 1234::bigint) * '10ms'::interval AS t
       FROM  generate_series(1,100000) AS elt;
      

      1234 常量是一个混淆键:选择您想要获得不同系列结果的任何其他bigint

      如果我们根据值的唯一性和区间的大小来检查结果:

       SELECT min(t),max(t),count(distinct t) FROM uniq_tstamp ;
      
                  min             |            max             | count  
      ----------------------------+----------------------------+--------
       2017-02-02 16:00:50.750651 | 2017-02-03 19:47:30.350651 | 100000
      (1 row)
      

      看一看第一个值:

       SELECT * FROM uniq_tstamp limit 10;
                   t              
      ----------------------------
       2017-02-03 14:42:44.420651
       2017-02-03 11:40:37.200651
       2017-02-02 17:28:50.470651
       2017-02-03 00:34:12.060651
       2017-02-03 00:02:16.780651
       2017-02-03 05:53:41.550651
       2017-02-02 21:53:49.900651
       2017-02-03 02:58:37.420651
       2017-02-03 05:25:00.730651
       2017-02-03 09:13:42.110651
      

      permuteseq 应用的随机化不是加密级别的,但它是合理的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-16
        • 2016-04-21
        • 1970-01-01
        • 2014-05-22
        • 1970-01-01
        • 2015-04-20
        • 1970-01-01
        相关资源
        最近更新 更多