最快的随机选择WHERE列X是Y(NULL)

时间:2012-05-20 22:29:19

标签: mysql sql

目前我正在使用:

SELECT * 
FROM 
  table AS t1
  JOIN (
    SELECT (RAND() * (SELECT MAX(id) FROM table where column_x is null)) AS id
  ) AS t2 
WHERE 
  t1.id >= t2.id
  and column_x is null
ORDER BY t1.id ASC
LIMIT 1

这通常非常快,但是当我将突出显示的column_x包含为Y(null)条件时,它会变慢。

什么是最快的随机查询解决方案,其中记录的列X为空?

ID是PK,列X是int(4)。表包含大约一百万条记录,总大小超过1 GB,目前每24小时翻一番。

column_x已编入索引。

列ID可能不是连续的。

本案例中使用的数据库引擎是InnoDB。

谢谢。

4 个答案:

答案 0 :(得分:3)

获得真正随机的记录可能会很慢。这个事实并没有真正解决这个问题;如果你想让它真正随机,那么查询必须加载所有相关数据,以便知道它必须选择哪些记录。

幸运的是,有更快捷的方法。它们并不是随意的,但是如果你乐于换取一点纯随机性来提高速度,那么它们应该足以满足大多数用途。

考虑到这一点,获取“随机”记录的最快方法是在数据库中添加一个额外的列,该列填充了随机值。也许主键的盐渍MD5哈希?随你。在此列上添加适当的索引,然后只需将该列添加到查询中的ORDER BY子句中,您将以随机顺序返回记录。

要获取单个随机记录,只需指定LIMIT 1并添加WHERE random_field > $random_value,其中随机值将是新字段范围内的值(例如随机数的MD5哈希值,对于例子)。

当然,这里的缺点是虽然你的记录将是随机顺序,但它们会被卡在相同的随机顺序中。我确实说它是查询速度的完美交易。您可以通过使用新值定期更新它们来解决这个问题,但我想如果您需要保持新鲜,那么这对您来说可能是一个问题。

另一个缺点是添加一个额外的列可能太多了,无法询问您是否存在存储限制,并且您的数据库规模已经很大,或者您是否有一个严格的DBA可以在添加列之前通过。但同样,你必须权衡一些事情;如果你想要查询速度,你需要这个额外的列。

无论如何,我希望有所帮助。

答案 1 :(得分:1)

您是否在查询上运行了explain?输出是什么?

为什么不存储或缓存SELECT MAX(id) FROM table where column_x is null的值并将其用作变量。您的查询将变为:

$rand = rand(0, $storedOrCachedMaxId);

SELECT * 
FROM 
  table AS t1
WHERE 
  t1.id >= $rand
  and column_x is null
ORDER BY t1.id ASC
LIMIT 1

db上更简单的查询可能会更容易。

要知道,如果您的数据包含相当大的漏洞 - 您不会通过这类查询得到一致的随机结果。

答案 2 :(得分:1)

我认为您不需要加入,也不需要订单,也不需要限制1(提供ID是唯一的)。

SELECT *
FROM   myTable
WHERE  column_x IS NULL
   AND id = ROUND(RAND() * (SELECT MAX(Id) FROM myTable), 0)

答案 3 :(得分:0)

我是MySQL语法的新手,但是进一步挖掘我认为动态查询可能会起作用。我们选择第N行,其中第N个是随机的:

SELECT @r := CAST(COUNT(1)*RAND() AS UNSIGNED) FROM table WHERE column_x is null;

PREPARE stmt FROM
'SELECT * 
FROM table
WHERE column_x is null
LIMIT 1 OFFSET ?';

EXECUTE stmt USING @r;