我正在使用PHP进行PostgreSQL。
是否可以选择列 FROM 表中的特定数量的随机值WHERE 条件 < / p>
而不是
选择列 FROM 表 WHERE 条件
然后将它们转换为数组并使用array_rand()
?
(我不想这样使用,因为我将拥有数百万行并首先选择所有值,然后array_rand()
可能需要花费很多时间。)
假设我有一张这样的表:
name | items
-----------+------------
Ben | {dd,ab,aa}
-----------+------------
David | {dd,aa}
-----------+------------
Bryan | {aa,ab,cd}
-----------+------------
Glen | {cd}
-----------+------------
Edward | {aa,cd}
-----------+------------
Aaron | {dd,aa}
-----------+------------
..... (many many more)
我需要选择匹配条件的一列(或基本上是10个随机行)中的10个随机值(在这种情况下为@> ARRAY[aa]
),而不进行顺序表扫描或时间 - 耗时。
order by random()
将花费大量时间,因为它必须处理每一行,所以我会选择更好的解决方案。
答案 0 :(得分:5)
在PostgreSQL中,你可以order by random()
,所以这应该是你想要的:
select name
from table
where items @>ARRAY['aa']
order by random()
limit 10;
答案 1 :(得分:1)
如果基表没有大量更新,此解决方案很好。其他维护成本可能超过收益。
如果您的条件始终为@> ARRAY[aa]
,则可以创建辅助查找表(基本上是物化视图)。
CREATE TABLE tbl_pick (rn serial, id int, PRIMARY KEY (rn, id);
INSERT INTO tbl_pick (id)
SELECT id FROM tbl
WHERE items @> ARRAY[aa];
然后您可以应用与描述here类似的方法:
SELECT *
FROM (
SELECT 1 + floor(random() * <insert_count_plus_a_bit_here>)::integer AS rn
FROM generate_series(1, 20) g
GROUP BY 1 -- trim duplicates
) r
JOIN tbl_pick USING (rn)
JOIN tbl USING (id)
LIMIT 10; -- trim surplus
这应该非常快,因为它只需要索引扫描,只能从表中读取~10行。
当然,您必须在(相关)INSERT / DELETE / UPDATE后更新tbl_pick
到tbl
。
可以向tbl_pick添加/删除少量更新(无更新),因为方法中有一些摆动空间。在进行一定数量的更新后,您需TRUNCATE
并重新运行完整的INSERT
。基本上重写您的物化视图。
UPDATE和DELETE可以使用tbl_pick
的外键约束级联到ON UPDATE CASCADE ON DELETE CASCADE
。并为新插入的行触发AFTER INSERT
。这一切都取决于基表中的可能性。
并安排定期重写tbl_pick,最好在下班时间。
如果你的随机选择查询突然爆发,有一个“变量”指示tbl_pick
是否脏(而不是fk约束和触发器)可能更便宜并且仅重新填充在运行查询之前的这种情况下的表(多次)。这在很大程度上取决于您的使用模式。这个“变量”可以是一行表,只允许UPDATE
。在(相关)更新tbl
后将其设置为TRUE,在刷新实体化视图后将其设置为FALSE。