使用选择查询加入postgres中的系列

时间:2014-08-29 15:06:59

标签: sql postgresql random row-number generate-series

我正在寻找一种方法来加入这两个查询(或者将这两个一起运行):

SELECT  s
FROM    generate_series(1, 50) s;

使用此查询:

SELECT id FROM foo ORDER BY RANDOM() LIMIT 50;

以这种方式得到50行:

series, ids_from_foo
1, 53
2, 34
3, 23

我已经在这里呆了几天了,我无法理解。任何帮助都会很棒。

2 个答案:

答案 0 :(得分:2)

使用row_number()

select row_number() over() as rn, a
from (
    select a
    from foo
    order by random()
    limit 50
) s
order by rn;

答案 1 :(得分:1)

从随机排序的表中挑选前n行是一种简单,简短,强力,但也可以方式随机选择50行。 所有行必须按此方式排序。

适用于中小型表或一次性临时使用。要在表上重复使用,有更有效的方法。 如果主键中的间隙/岛的比率较低,请使用:

SELECT row_number() OVER() AS rn, *
FROM (
   SELECT *
   FROM  (
       SELECT floor(random() * 999999)::int AS foo_id
       FROM   generate_series(1, 55) g
       GROUP  BY 1                     -- trim duplicates
       ) sub1
   JOIN   foo USING (foo_id)
   LIMIT  50
   ) sub2;

这将是毫秒(或更少)的问题,无论表格多大
使用EXPLAIN ANALYZE将性能与替代解决方案进行比较。

解释

  • 999999是表格的估计行数,向上舍入。替换为:

    的结果
    SELECT reltuples FROM pg_class WHERE oid = 'foo'::regclass;
    

    向上舍入以轻松包含自上次ANALYZE以来可能的新条目。您也可以动态地在通用查询中使用表达式本身,它很便宜。详细说明:

  • 55是您在结果中所需的行数(50),乘以一个较低的因子,可以轻松弥补表格中的差距比率(不太可能,但可能)重复随机数。

  • 不言而喻,foo_id必须编入索引。主键很好用。

  • 如果您的主键未在1附近开始(不必完全为1,则覆盖间隙),请将最小pk值添加到计算中:

    min_pkey + floor(random() * 999999)::int
    

详细解释在此相关答案中: