我已经知道通过random()排序是检索随机行的最糟糕方式。我已经实现了添加random_number列并在检索随机行时使用该列的解决方案,然后在每次检索时更新random_number。所有这些都用于参加返回随机代理IP的服务:
select proxy_ip from proxy where random_number > 0.63 limit 1
0.63只是应用程序内部生成的随机数的一个示例。
当我使用"最糟糕的"溶液:
select proxy_ip from proxy
order by random()
limit 1
调用服务时似乎运行得更快。该表包含9300行,所以我的问题是,表格必须包含多少行才能使sort by random()
成为最差的解决方案?
在应用程序中引入了一些不直接与db一起工作的开销,而是使用数据层来反过来运行查询,这解释了为什么更好的解决方案运行缓慢(除此之外)对db执行1次以上的查询,而不仅仅是1,因为它需要更新random_number)。
解释分析的结果:
SORT BY RANDOM()
Limit (cost=837.03..837.03 rows=1 width=18) (actual time=34.954..34.956 rows=1 loops=1)
-> Sort (cost=837.03..860.46 rows=9373 width=18) (actual time=34.950..34.950 rows=1 loops=1)
Sort Key: (random())
Sort Method: top-N heapsort Memory: 25kB
-> Seq Scan on proxy (cost=0.00..790.16 rows=9373 width=18) (actual time=0.013..17.951 rows=9363 loops=1)
Total runtime: 34.993 ms
使用随机栏:
Limit (cost=0.00..0.23 rows=1 width=18) (actual time=0.038..0.045 rows=1 loops=1)
-> Seq Scan on proxy (cost=0.00..790.16 rows=3481 width=18) (actual time=0.029..0.029 rows=1 loops=1)
Filter: (random_number > 0.63::double precision)
Total runtime: 0.078 ms
该表有1个索引:
CREATE UNIQUE INDEX proxy_pkey ON proxy USING btree (id)
答案 0 :(得分:1)
请参阅此帖子How to retrieve randomized data rows from a postgreSQL table?
链接到一个非常明亮的Postgres家伙(Depesz)网站,载有大量信息。 - > Depesz MY THOUGHTS ON GETTING RANDOM ROW
通过这些信息尝试一些不同的方式,看看什么是最好的。
答案 1 :(得分:1)
几点想法......
您的问题的答案将是非常硬件和特定于实现的。在现代硬件上,9300行并不是很多。有可能是你的整个表在第一次读取后存储在内存中。因此,后续的ORDER BY RANDOM()
查询会非常快。
您还因为没有索引该列而损害了随机数列的性能,这意味着您仍然必须基本上读取整个表以避免...必须读取整个表
因此,在random_number列中添加一个索引,看看它有何帮助。
您也可以通过更新来减少所需的往返次数,并同时选择以下内容:
UPDATE proxy
FROM (
SELECT id
FROM proxy
ORDER BY random_number
LIMIT 1
) AS r
SET random_number=RANDOM()
WHERE proxy.id=r.id
RETURNING proxy.*
您并不是真的以这种方式随机化您的代理服务器。假设你有5台服务器,A-E,它们最初被分配为1-5的随机数:
A: 1
B: 2
C: 3
D: 4
E: 5
在第一次运行时,您将选择服务器A,random_number为1.然后为其分配一个新的随机数1-5。让我们说你得到3:
B: 2
C: 3
A: 3
D: 4
E: 5
第二次运行时,你得到B,然后给它分配一个新的随机数,比如4:
C: 3
A: 3
D: 4
B: 4
E: 5
然后你得到C,给它一个新的随机数,2:
C: 2
A: 3
D: 4
B: 4
E: 5
应该很容易看出你将如何挨饿你的一些服务器......任何服务器“不吉利”足以显示在列表的末尾,可能会永远留在那里。
< / LI>一个更好的,实际上是随机的方法,是为每个服务器分配一个指定范围内的静态数字,然后随机选择那个数字(或用哈希伪随机) 。这对于性能更好,因为你没有做大量的写操作,而且它实际上是随机的!
SELECT proxy_ip
FROM proxy
WHERE id=(RANDOM()*9300)::INT