4

我一直没有问,因为我觉得这个问题被问了这么多,但仍然缺乏明确的答案:

对象表:40M+ 行,以 UPC、EIN、ISBN 作为 obj_id 主键填充。差距

*Obj_Cat* 表:将对象链接到类别。|的列 obj_id | cat_id |

问题:返回 5 个非顺序随机 obj_id 的最佳方法是什么?有没有比我列出的更好的方法?

解决方案1: SELECT objects.obj_id FROM objects left join obj_cat on objects.obj_id=obj_cat.obj_id WHERE obj_cat.cat_id=cat_id ORDER BY RAND() LIMIT 1;运行5次

  • 大桌子很慢。

解决方案2: SELECT obj_id FROM objects WHERE obj_id >= (SELECT FLOOR( MAX(obj_id) * RAND()) FROM objects) LIMIT 1;运行5次(不包括obj_cat join,让它更容易理解)

  • 如果您的行没有间隙或间隙可忽略不计,则为最佳解决方案。非常快。

  • 不适用于类别,因为编号不可避免地会出现空白。

解决方案3: SELECT FLOOR(RAND() * COUNT(objects.*)) AS偏移FROM objects, obj_cat WHERE objects.obj_id=obj_cat.obj_id AND obj_cat.cat_id=cat_id; SELECT obj_id FROM objects LIMIT $offset, 1运行5次

  • 非常灵活。比解决方案 1 快得多。适用于间隙。但在 40M+ 行时,单个 'LIMIT $offset, 1' 仍可能需要 1 分钟。

我使用了解决方案 3,但速度很慢。我目前的解决方案是移动使用 Solr randomsortfield,因为在 fq 中指定我的类别很容易。

索尔解决方案: ?q=*&fl=obj_id&fq=cat:(cat_id)&sort=random_* desc&rows=5

  • 相当快,每个类别大约需要 45 秒,但会在运行中返回 5 个非顺序结果。

人们在处理大型数据集时是否发现了更好的方法?我知道这似乎是一个重复的问题,但我想我会用 40M+ 表贡献我的经验。

4

1 回答 1

0

对于这么大的数据集,您无法进行这样的即时计算。您需要利用时间记忆权衡。在 obj_cat 表中创建一个新的无符号整数索引列,其宽度大于最大行数,并用随机数填充每一行。这样,您可以简单地生成一个随机数并直接选择最接近的匹配五次。这将比尝试使用 ORDER BY RAND() 快几个数量级。

于 2012-05-18T14:43:34.130 回答