MySQL使用WHERE子句平均分配随机行

Kev*_*aat 5 mysql sql database

我有这张桌子,

person_id   int(10) pk
points      int(6) index
other columns not very important
Run Code Online (Sandbox Code Playgroud)

我有这个随机函数,在具有10M行的表上非常快:

SELECT person_id
  FROM persons AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(person_id)
                        FROM persons)) AS id)
        AS r2
 WHERE r1.person_id >= r2.id
 ORDER BY r1.person_id ASC
 LIMIT 1
Run Code Online (Sandbox Code Playgroud)

这一切都很棒但现在我希望只显示点> 0的人.示例表:

PERSON_ID      POINTS
1              4
2              6
3              0
4              3
Run Code Online (Sandbox Code Playgroud)

当我附加AND points > 0到where子句时,不能选择person_id 3,因此创建间隙,并且当随机选择person_id 3时,将选择person_id 4.这给了人4更大的选择机会.任何人都有建议我如何调整查询以使其与where子句一起使用,并为所有行提供相同的选择机会百分比.

信息表:该表是统一的,person_id中没有间隙.大约90%将获得0分.我想查询points = 0和points> 0的位置.

有人说之前,请使用rand():对于行数超过100k的表,这不是解决方案.

额外问题:是否可以在1个查询中选择x个随机行,所以当我想要更多随机行时,我不必多次调用此查询?

重要提示:性能是关键,查询的10M +行可能不会比当前查询花费更长的时间,这需要0.0005秒,我宁愿保持在0.05秒以下.

最后一点:如果您认为查询永远不会满足上述要求,但是另一种解决方案是可能的(比如获取100行并显示x随机值超过0点),请告诉:)

非常感谢您的帮助,欢迎所有帮助:)

小智 1

您可以为您真正想要使用的记录生成内联无间隙 ID,然后使用可用记录总数生成随机选择器。

尝试使用此(支持此处为 row_number 生成器选择的答案):

    SELECT r1.*
    FROM
        (SELECT  person_id,
                 @curRow := @curRow + 1 AS row_number
        FROM persons as p,
             (SELECT @curRow := 0) r0
        WHERE points>0) r1
    , (SELECT COUNT(1) * RAND() id
       FROM persons
       WHERE points>0) r2
    WHERE r1.person_id>=r2.id
    ORDER BY r1.person_id ASC
    LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

你可以在这个 sqlfiddle中搞乱它。