Php MySQL邻域中的随机行

Php MySQL邻域中的随机行,php,mysql,sql,sorting,random,Php,Mysql,Sql,Sorting,Random,我有一张2500万行的桌子: ID int(10) PK points int(6) INDEX some other columns 我想向用户显示4个随机行,它们在点上彼此有点接近。我在搜索和调整生成随机行后发现了这个查询,速度非常快: SELECT person_id, points FROM persons AS r1 JOIN (SELECT (RAND() * (SELECT MAX(person_id)

我有一张2500万行的桌子:

ID int(10) PK
points int(6) INDEX
some other columns
我想向用户显示4个随机行,它们在点上彼此有点接近。我在搜索和调整生成随机行后发现了这个查询,速度非常快:

SELECT person_id, points
FROM persons AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(person_id)
                        FROM persons)) AS id)
        AS r2
 WHERE r1.person_id>= r2.id and points > 0
 ORDER BY r1.person_id ASC
 LIMIT 4
所以我在PHP中查询它。这让我在热身时在0.05秒以下获得了快速的好成绩。但这些行实际上只是随机的,至少有一个点,因为点>0。我想显示一些有点接近的行,不一定每次都是,但假设我使用限制50进行查询,然后在PHP中选择一个随机行,并根据它旁边的点选择3个最近的行。我认为您需要对结果进行排序,选择一个随机行,并显示它后面/前面的行。但我不知道如何做到这一点,因为我对PHP非常陌生

任何人提出建议,欢迎所有反馈:

在您的积分栏上建立一个索引(如果它不存在),然后对其执行随机逻辑:

改变表格,增加索引点; 选择人员id,点 由人加入 选择RAND*MAXpoints作为轴 来自个人 其中点>0 t轴上的t轴0 随机0上的r 按个人编号订购 限制1
从中删除子查询将极大地提高性能和缓存,例如,您可以获取ID列表,将其放入文件中,然后从中随机读取,例如从文件中读取随机行。这将大大改进它,因为您可以看到,您是否将对该查询运行EXPLAIN,并通过更改查询以仅加载4个仍然随机的ID的数据来进行比较。

我建议在PHP中执行两个单独的sql查询,而不是对它们进行联接/子查询。在许多情况下,优化器无法简化您的查询,必须单独执行每个查询。所以,在你的情况下。如果您有1000人,优化器将在最坏情况下执行以下操作:

排1000人 为每个获得1000人行的人进行子选择 用连接的行连接1000人,形成1.000.000行 过滤所有这些 简言之: 1001个查询,包含1.000.000行

我的建议

执行两个查询,不进行连接或子选择,因为在大多数情况下,这两个查询(尤其是组合查询)的性能都会显著下降

选择人员id,点 来自个人 按兰特限购1 现在将找到的点用于第二个查询

选择人员id、点、点-作为距离 来自个人 按距离订购ASC限制4
查询时间从0.05秒到2.6213秒。在优化表的问题上,你有点索引吗?是的,它有一个索引,它的子选择总是有问题的。在大多数情况下,优化器必须为主选择中的每一行运行子选择。。。这是非常糟糕的。我会做两个不同的查询。应该快得多。另一方面,如果子选择只返回一个列而不执行联接,则可以直接作为列执行子选择。如果您仍然想作为子选择来执行,这也应该会提高性能。要理解您的意思,请您解释一下好吗?您应该明确地在此处选中explain,查看它只执行子查询一次,而不是针对每一行。不过应该行@eggyal,在测试之后,我发现只有较低的点行被选中,当我有300行都在1到100点之间时,我只会在点在1到20之间的情况下随机尝试60次。。这怎么可能?@eggyal,谢谢你,伙计。最后一个问题,您似乎比我更了解SQL:假设我有300人在表中,分数在1-100之间。假设5个人有23个点作为例子,此查询将始终选择前4个,是否有可能给他们所有人一个均等的机会在反随机函数中出现?因为我想让每个人都有同样%的机会被展示出来。@KevinVermaat:请参阅我的更新。@eggyal我试图将这两个sql查询合并为一个sql查询,但我仍然得到了某些点的第一个结果:/我做错了什么?但愿我是像你一样的专家。你的第一个查询需要3.0974秒来执行。我确实读过很多关于这么大的表的随机行的书,避免按兰德排序是明智的;还有别的选择吗?顺便说一句,上面的解决方案仍然使用RAND,但作为列,不在where条件内。这也可以在这里完成,这个答案的要点是将geting random和Get其他行分成两个查询;好的,我分析了上面的随机化@eggyal的方法。它似乎真的工作得很好,加上在范围内得到4个项目的附加数学,这应该是一条路要走。公众的观点似乎仍然认为PHP在很多情况下都会更糟糕,也许不是这一个……不,这不是真的,我确实读了很多关于它的书,而且它相当复杂,但例如,ToBe的答案需要3秒钟才能执行,@eggyal的答案需要0.006秒seconds@KevinVermaat什么是不正确的
? 这种方法不会优化吗?当然会的!从文件中随机读取4行要比从数据库中随机获取4个ID快得多:。虽然不是sql方式,但它可以工作。嘿,对不起,我读得太快了,你是对的,但不幸的是,我需要DB解决方案。出于安全原因,我认为许多在线应用程序不能使用文件读取或写入数据。此外,数据库还有许多优点,如内置完整性(如FK)和事务性写入。@KevinVermaat这是一个非常错误的说法。写入/读取决不是违反安全性的行为,如果不读取文件,您甚至无法导入它们。即使现在已经死了,谢天谢地,安全模式也没有阻止这一点。