优化我的mysql语句太慢了
所以我有一个超过80000条记录的表,这个叫做系统。我还有另一张表,叫做follows 我需要我的语句从系统表中随机选择记录,其中当前userid下的下表中尚未列出该id 这就是我所拥有的:优化我的mysql语句太慢了,sql,mysql,random,Sql,Mysql,Random,所以我有一个超过80000条记录的表,这个叫做系统。我还有另一张表,叫做follows 我需要我的语句从系统表中随机选择记录,其中当前userid下的下表中尚未列出该id 这就是我所拥有的: SELECT system.id, system.username, system.password, system.followed, system.isvalid, follo
SELECT system.id,
system.username,
system.password,
system.followed,
system.isvalid,
follows.userid,
follows.systemid
FROM system
LEFT JOIN follows ON system.id = follows.systemid
AND follows.userid = 2
WHERE system.followed = 0
AND system.isvalid = 1
AND follows.systemid IS NULL
ORDER BY RAND()
LIMIT 200
现在它工作得非常好,只是它甚至需要花整整一分钟的时间才能开始用它选择的记录处理手头的工作。此时,脚本通常会超时,而不会发生任何事情
有人能告诉我如何重做这个,所以同样的想法是这样做的,但它不是使用兰德订单?这似乎把事情拖慢了很多
谢谢 我不确定是否有一个简单的解决方案来取代您的查询,下面是一篇关于纠正此类问题的文章
您可以根据ID和当前时间生成一些伪随机值:
ORDER BY 37*(UNIX_TIMESTAMP() ^ system.id) & 0xffff
将从id混合咬入,然后只取最低的16个。速度缓慢的主要原因有两个:
- SQL必须首先为每一行发出一个随机数
- 然后,必须根据该数字对行进行排序,以选择前200行
CREATE [UNIQUE ?] INDEX
ON system (id, RandPreFilter)
并按如下方式更改查询
SELECT system.id
, system.username
, system.password
, system.followed
, system.isvalid
, follows.userid
, follows.systemid
FROM system
LEFT JOIN follows ON system.id = follows.systemid
AND follows.userid = 2
WHERE system.followed=0 AND system.isvalid=1
AND follows.systemid IS NULL
AND RandPreFilter = 1 -- or other numbers, or possibly
-- FLOOR(1 + RAND() * 25)
ORDER BY RAND()
LIMIT 200
<> P>查询速度较慢的原因是,数据库需要保留所有生成的随机值和它们各自的数据的表示,然后才能从数据库返回单个行。您可以做的是通过使用RAND(RAND)来限制要优先考虑的候选行数。
如果您不要求查询为每次调用返回不同的结果,您还可以添加一个带有索引的预生成随机值列,并与上述技术相结合。这将允许您以公平的方式获取任意数量的样本,即使您添加或删除行,但对相同数据的相同查询当然会返回相同的结果结果集。根据数据的随机性,可能需要对数据进行排序,并添加一个额外的“上次使用”日期时间列,并在使用数据后进行更新。然后按上次使用字段降序选择前n行 如果将其包装在一个准备好的语句中,则可以一次选择一个(半)随机结果,而不必担心逻辑
或者,为每一行指定一个顺序ID,并在代码中生成随机性,然后只提取所需的行。问题是,在订购之前会返回完整的记录集。可能有点晚,但至少这里有一个额外的解决方案供将来考虑:
SELECT minSystem.id,
minSystem.username,
minSystem.password,
minSystem.followed,
minSystem.isvalid,
randFollows.userid,
randFollows.systemid
FROM
(
SELECT *
FROM system
WHERE system.followed = 0 AND system.isvalid = 1
) as minSystem
LEFT JOIN
(
SELECT *
FROM (
SELECT *
FROM follows
WHERE follows.systemid IS NULL
) as minFollows
WHERE rand() <= 200 * 1.5 / (SELECT count(*) FROM follows WHERE systemid IS NULL)
) as randFollows
ON minSystem.id = randFollows.systemid
LIMIT 200
选择minSystem.id,
minSystem.username,
minSystem.password,
接下来是,
minSystem.isvalid,
rand.userid,
rand.systemid
从…起
(
挑选*
从系统
其中system.isvalid=0和system.isvalid=1
)as minSystem
左连接
(
选择*
从(
挑选*
从下面
其中follows.systemid为NULL
)如下
其中rand()你的连接字段有什么索引?这可能是一个很大的瓶颈。我不太确定你的意思…@Brandon我知道现在做这件事有点晚了,但是如果你想用一种半简单化的方法来做,你可以把它放在一个子查询中。更多细节请参阅我的答案可能重复感谢,但这不是一种可行的方法这个查询是有效的。为什么不呢?在那篇文章中有很多不同的解决方案,其中一些我认为对你有用。你的id字段是自动递增字段吗?如果是的话,选择随机id的解决方案应该是有效的。