Mysql 按兰德排序()备选方案

Mysql 按兰德排序()备选方案,mysql,performance,random,Mysql,Performance,Random,可能重复: 我目前有一个查询,它以按兰德(HOUR(NOW())的顺序结束限制40,以获得40个随机结果。结果列表每小时都会更改 这会杀死查询缓存,从而破坏性能 你能推荐一种获得随机(ish)结果集的替代方法吗?它不一定是每小时,也不一定是完全随机的 我更喜欢随机结果,而不是在表中的任意字段上排序,但作为最后手段,我会这样做 (这是一个新产品的列表,我想时不时地对其进行一些调整)。它会终止缓存,因为每次都需要不同的结果集。无法缓存一组随机值。如果要缓存一组结果,请缓存一个大的随机值集,然后在将

可能重复:

我目前有一个查询,它以按兰德(HOUR(NOW())的顺序结束
限制40
,以获得40个随机结果。结果列表每小时都会更改

这会杀死查询缓存,从而破坏性能

你能推荐一种获得随机(ish)结果集的替代方法吗?它不一定是每小时,也不一定是完全随机的

我更喜欢随机结果,而不是在表中的任意字段上排序,但作为最后手段,我会这样做


(这是一个新产品的列表,我想时不时地对其进行一些调整)。

它会终止缓存,因为每次都需要不同的结果集。无法缓存一组随机值。如果要缓存一组结果,请缓存一个大的随机值集,然后在将要使用这些值的时间的子部分内[在sql之外]在较小的值集中执行随机抓取操作。

实现该操作的一种方法是将数据映射到的对象无序排列。如果不将数据映射到对象,则可以从数据库中洗牌结果数组。我不知道这是否会更好,但您至少会从查询缓存中获得您提到的好处


您还可以生成从1到n的随机序列,并用这些序列为结果数组(或对象数组)编制索引。

您可能有一列包含随机值,每小时更新一次。

如果您有ID列,最好执行以下操作:

-- create a variable to hold the random number
SET @rownum := SELECT count(*) FROM table;
SET @row := (SELECT CEIL((rand() * @rownum));

-- use the random number to select on the id column
SELECT * from tablle WHERE id = @row;
选择随机id号的逻辑可以移动到应用程序级别

SELECT * FROM table ORDER BY RAND LIMIT 40

这是非常低效的,因为MySQL将处理表中的所有记录,对所有行执行完整的表扫描,随机排序。

计算PHP代码中的当前小时数,并将其传递给查询。这将产生一个可以缓存的静态值


请注意,您可能还有一个隐藏的bug。由于只计算小时,因此只有24个不同的值,每天都会重复。这意味着今天下午1点的节目也将与明天下午6点的节目相同。您可能需要更改它。

不要与缓存发生冲突,请打开它

按原样编写查询(甚至更简单)。然后,在代码中缓存结果,将缓存到期时间设置为1小时。如果您使用的是缓存层,如memcached,则设置为。如果没有,您可以构建一个相当简单的:

[pseudocode]
global cache[24]
h = Time.hour
if (cache[h] == null) {
  cache[h] = .. run your query
}
return cache[h];

我认为更好的方法是将产品标识符下载到中间层,在需要时随机选择40个值(每小时一次或每个请求一次),并在查询中使用它们:
product\u id in(@id\u 1,@id\u 2,…,@id\u 40)
如果您每小时只需要一组新的随机数据,不要点击数据库-将结果保存到应用程序的缓存层(或者,如果没有缓存层,只需将其放入某种临时文件)。查询缓存很方便,但如果您甚至不需要执行查询,那就更好了……

如果需要将大型数据集按随机顺序排序(这确实需要排序),那么这将是一个非常糟糕的查询,然后丢弃除前40条记录以外的所有记录

一个更好的解决方案是只挑选40条随机记录。有很多方法可以做到这一点,这通常取决于有均匀分布的关键点


另一种选择是在每小时只运行一次的批处理作业(或其他)中随机选取40条记录,然后记住它们是哪些记录。

您能否提供一些有关您在其中编写代码的见解?我建议您在代码中而不是sql中执行此操作。您能在应用程序级别缓存它吗?嗯,我只希望它每小时左右更改一次,因此在一小时内它将被修复。这就是我当前查询产生的结果,使用rand()的缺点是无法缓存结果;e、 g.memcached或其他应用层缓存就可以了。小时只是用作随机数生成器的种子。是的,我知道我每天下午2点都会得到相同的结果,但这很好(除非产品列表以任何方式发生变化)+1这通常是一个好的解决方案,除非@rikh正在运行亚马逊或eBay(即数百万种产品)。内存中的ID可能对其他优化也有用。表可能在中间某个地方缺少ID,所以正确的选择将在结尾:<代码>选择*,从表中的ID > = @行限制1;<代码>