我希望能够从数据库中提取15个左右的记录.我已经看到WHERE id = rand()
随着数据库变大,使用会导致性能问题.我见过的所有解决方案都是为了选择单个随机记录.我想得到倍数.
有谁知道为大型数据库执行此操作的有效方法?
编辑:
进一步编辑和测试:
我在使用MyISAM的新数据库上创建了一个相当简单的表.我给了这3个字段:( autokey
无符号自动数字键)bigdata
(大blob)和somemore
(中等int).然后我将随机数据应用到表中并使用Navicat运行一系列查询.结果如下:
Query 1: select * from test order by rand() limit 15
Query 2: select *
from
test
join
(select round(rand()*(select max(autokey) from test)) as val from test limit 15) as rnd
on
rnd.val=test.autokey;`
Run Code Online (Sandbox Code Playgroud)
(我尝试了选择和选择不同,它没有明显的区别)
和:
Query 3 (I only ran this on the second test):
SELECT *
FROM (
SELECT @cnt := COUNT(*) + 1,
@lim := 10
FROM test
) vars
STRAIGHT_JOIN
(
SELECT r.*,
@lim := @lim - 1
FROM test r
WHERE (@cnt := @cnt - 1)
AND RAND(20090301) < @lim / @cnt
) i
Run Code Online (Sandbox Code Playgroud)
ROWS: QUERY 1: QUERY 2: QUERY 3: 2,060,922 2.977s 0.002s N/A 3,043,406 5.334s 0.001s 1.260
我想做更多的行,所以我可以看到查询3如何缩放,但此刻,似乎明显的赢家是查询2.
在我完成此测试并声明答案之前,当我设置了所有这些数据和测试环境时,是否有人可以推荐任何进一步的测试?
尝试:
select * from table order by rand() limit 15
Run Code Online (Sandbox Code Playgroud)
另一种(可能更有效的方式)是加入一组随机值.如果表中有一些连续的整数键,这应该可以工作.这是我将如何在postgres中做到这一点(我的MySQL有点生疏)
select * from table join
(select (random()*maxid)::integer as val from generate_series(1,15)) as rnd
on rand.val=table.id;
Run Code Online (Sandbox Code Playgroud)
其中maxid是最高id
的table
.如果id
有一个索引,那么这意味着只有15个索引查找,所以它非常快.
更新:
看起来MySQL中没有generate_series这样的东西.我的错.我们实际上不需要它:
select *
from
table
join
-- this just returns 15 random numbers.
-- I need `table` here only to produce rows for rand()
(select round(rand()*(select max(id) from table)) as val from table limit 15) as rnd
on
rnd.val=table.id;
Run Code Online (Sandbox Code Playgroud)
PS如果我不想返回重复项,我可以在随机生成器表达式中使用(选择distinct [...]).