我正在寻找一种方法来加入这两个查询(或者将这两个一起运行):
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
我已经在这里呆了几天了,我无法理解。任何帮助都会很棒。
答案 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
详细解释在此相关答案中: