【问题标题】:randomizing large dataset随机化大型数据集
【发布时间】:2010-08-24 16:27:46
【问题描述】:

我正在尝试找到一种从大型数据集中随机选择的方法。

我们预计数据集将增长到约 50 万条记录,因此找到一种在数据集增长时保持良好表现的方法非常重要。

我尝试了一种来自 http://forums.mysql.com/read.php?24,163940,262235#msg-262235 的技术,但它并不是完全随机的,而且它不能很好地与 LIMIT 子句配合使用,你并不总能得到你想要的记录数。

所以我想,由于 PK 是 auto_increment,我只需生成一个随机 id 列表并使用 IN 子句来选择我想要的行。这种方法的问题在于,有时我需要一组随机数据,其中记录具有特定状态,这种状态最多占总组的 5%。要完成这项工作,我首先需要找出我可以使用的具有特定状态的 ID,所以这也行不通。

我使用的是 mysql 5.1.46,MyISAM 存储引擎。
重要的是要知道选择随机行的查询将非常频繁地运行,并且它正在从中选择的表被频繁地附加到。

任何帮助将不胜感激!

【问题讨论】:

    标签: mysql random


    【解决方案1】:

    你可以通过一些非规范化来解决这个问题:

    • 构建一个包含与数据表相同的 pkey 和状态的辅助表
    • 添加并填充状态组列,该列将是一种您自己自动编号的子键(相对于单个状态的基于 1 的自动增量)
    Pkey    Status    StatusPkey
    1       A         1
    2       A         2
    3       B         1
    4       B         2
    5       C         1
    ...     C         ...
    n       C         m (where m = # of C statuses)
    

    当您不需要过滤时,您可以如上所述在 pkey 上生成 rand #s。当您确实需要过滤时,然后针对您感兴趣的特定状态的 StatusPkeys 生成 rands。

    有几种方法可以构建此表。您可以有一个定期运行的程序,也可以实时执行。后者会影响性能,因为计算 StatusPkey 可能会很昂贵。

    【讨论】:

    • 这个方法也想到了,但是觉得太贵了。那时我没有意识到它最多只占总数的 5%(我认为它会更大)。所以我认为这是我将采取的方法。不过,我将为此创建一个后台进程,不希望我的前端性能受到影响。
    • 按时间间隔填充(或重新创建)表怎么样?一天一次还是一小时一次?还是需要近乎实时?
    • 这就是我打算做的事情,我将为此安装一个 crontab。我认为我可以将更新频率保持在相当高的水平(例如,每五分钟一次),因为我可以在状态更改时进行注册。所以我所要做的就是检查“脏”标志并重新填充表格! (如果我跟踪确切的状态更新,我什至可以完成更新)。
    【解决方案2】:

    查看 Jan Kneschke 的 this article...它很好地解释了解决此问题的不同方法的优缺点...

    【讨论】:

    • 文章中的第一句话是:“对于第一个示例,我们假设 be ID 从 1 开始,并且在 1 和 ID 的最大值之间没有空洞。”。这正是我面临的问题:我确实有漏洞。
    • 阅读。 adding holes to the numbersMaintaining the holes Table with Triggers 有一整节...
    • 我明白了.. 判断得太快了!他建议采用与 Paul Sasik 相同的方法,所以我想我们在这里很好!
    【解决方案3】:

    您可以有效地执行此操作,但您必须在两个查询中执行此操作。

    首先获得一个随机偏移量,按符合您的 5% 条件的行数缩放:

    SELECT ROUND(RAND() * (SELECT COUNT(*) FROM MyTable WHERE ...conditions...))
    

    这将返回一个整数。接下来,在LIMIT 表达式中使用整数作为偏移量:

    SELECT * FROM MyTable WHERE ...conditions... LIMIT 1 OFFSET ?
    

    并非所有问题都必须在单个 SQL 查询中解决。

    【讨论】:

    • 所以你的意思是执行两次查询。然后倾斜超过可能的数十万行?我不一定称它为有效...更好的方法(使用您的两个查询方法)是在第二个查询中添加一个WHERE id >= ? LIMIT 1。这样它就不需要加载前 n 行来找到你想要的行(它可以缩短那个步骤并应用显着的优化)...
    • 这种方法的问题是您一次只能检索一条记录。当您增加 limit 时,它不再是随机集,它只是随机的偏移量。
    • @ircmaxell:偏移量不是 id 值。使用WHERE id >= ? 是非随机的,出现在间隙之后的行会以更高的频率被拾取。
    • @Dennis Haarbrink:是的,这种技术对于一次选择一个随机行很有用。
    • 如果我们要选择几行怎么办?
    猜你喜欢
    • 2012-04-19
    • 2018-07-30
    • 1970-01-01
    • 2019-03-13
    • 2019-11-21
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 2022-05-21
    相关资源
    最近更新 更多