1

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

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

我已经做了几天了,我无法弄清楚。任何帮助都会很棒。

4

2 回答 2

2

利用row_number()

select row_number() over() as rn, a
from (
    select a
    from foo
    order by random()
    limit 50
) s
order by rn;
于 2014-08-29T15:10:27.673 回答
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;

这将是毫秒(或更短)的问题,无论 table 有多大
将性能与替代解决方案进行比较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
    

此相关答案中的详细说明:

于 2014-08-29T17:14:23.477 回答