我正在寻找一种方法来加入这两个查询(或一起运行这两个):
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
我已经做了几天了,我无法弄清楚。任何帮助都会很棒。
我正在寻找一种方法来加入这两个查询(或一起运行这两个):
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
我已经做了几天了,我无法弄清楚。任何帮助都会很棒。
利用row_number()
select row_number() over() as rn, a
from (
select a
from foo
order by random()
limit 50
) s
order by rn;
从随机排序的表中挑选前 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
此相关答案中的详细说明: