2

我已经知道通过 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,不仅是 1,因为它需要更新 random_number)。

解释分析的结果:

随机排序()

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)
4

2 回答 2

1

请参阅这篇文章如何从 postgreSQL 表中检索随机数据行?

它链接到一个非常聪明的 Postgres 人 (Depesz) 网站,其中包含大量重要信息。-> Depesz 我对获得随机行的想法

有了这些信息,尝试一些不同的方法,看看哪种方法效果最好。

于 2012-12-12T20:25:17.963 回答
1

几个想法...

  1. 您的问题的答案将是非常特定于硬件和实现的。9300 行在现代硬件上并不是很多。第一次读取后,您的整个表可能会存储在内存中。所以后续的ORDER BY RANDOM()查询会很快。

  2. 您还通过不索引该列来损害随机数列的性能,这意味着您仍然必须基本上读取整个表以避免......必须读取整个表。

    因此,为您的 random_number 列添加一个索引,看看它有什么帮助。

  3. 您还可以通过执行更新和同时选择来减少必要的往返次数,例如:

    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.*
    
  4. 您并没有以这种方式真正随机化您的代理服务器。假设您有 5 台服务器 AE,它们最初分配的 random_numbers 为 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
    

    应该很容易看出您将如何饿死您的一些服务器......任何“不幸”到足以出现在列表末尾的服务器,可能会永远留在那里。

  5. 一种更好的,实际上是随机的方法,是在指定范围内为每个服务器分配一个静态数字,然后随机选择数字(或使用哈希伪随机)。这对性能更好,因为您没有进行大量写入,而且它实际上是随机的!

    SELECT proxy_ip
    FROM proxy 
    WHERE id=(RANDOM()*9300)::INT
    
于 2012-12-13T08:55:02.917 回答