我需要有关执行时间过长或根本不执行的 mysql 查询的帮助。
(我正在尝试做的是更复杂问题的一部分,我想创建 PHP cron 脚本,它将执行一些繁重的查询并根据返回的结果计算数据,然后使用这些数据将其存储在数据库中以供使用更方便的使用。很可能我会在这里对这个过程提出疑问。)
首先让我们尝试解决这些繁重查询的问题之一。
事情是这样的:
我有表:users_bonitet。此表包含字段:id、user_id、bonitet、tstamp。
首先要注意:当我说用户时,请理解用户实际上是公司,而不是人。所以 user.id 是某个公司的 ID,但由于某些其他原因,我在这里使用的表称为“users”。
users_bonitet表中的三个关键字段是:user_id(引用user.id),bonitet(代表用户的强度,它可以有 3 个值,1 - 2 - 3,其中 3 是最好的)和 tstamp(存储 bonitet 插入的时间。每次当某些用户的 bonitet 值发生变化时,新行插入 tstamp该插入物,当然还有新的 bonitet 值。)。所以基本上有些用户可以将 bonitet 设置为 1,表示他处境不佳,但一段时间后它可以变为 3,表示他做得很好,并且该更改的时间存储在 tstamp 中。
现在,我将仅列出我们需要在查询中使用的其他表,然后我将解释原因。表是:user、club、club_offer 和 club_territories。
一些用户(公司)是俱乐部的成员。俱乐部成员可以获得一些俱乐部优惠(他向人们和其他俱乐部成员代表他的产品)并且他在一些领土上经营。
我需要做的是为每个俱乐部报价(由某个俱乐部成员(member)的用户提供)获取 bonitet 值(value),但仅限于 ID 为 1100000 的特定区域;由于每个用户的 bonitet 值都在随时间变化,这意味着我只需要获取最新的值。因此,如果某些用户在 2012 年 1 月 21 日的 bonitet 为 1,但后来在 2012 年 5 月 26 日更改为 2,我只需要获取 2,因为这是当前值。
我用我现在正在使用的示例数据库模式和查询制作了一个 SQL Fiddle。在这个小数据库上,查询正在按我的要求工作,而且速度很快,但在真实数据库上它非常慢,有时根本不执行。
在这里查看:http://sqlfiddle.com/#!9/b0d98/2
我的问题是:我是否使用了错误的查询来获取所有这些数据?我得到了正确的结果,但也许我的查询不好,这就是它执行如此缓慢的原因?我怎样才能加快速度?我尝试过使用 phpmyadmin 放置索引,但没有太大帮助。
这是我的查询:
SELECT users_bonitet.user_id, users_bonitet.bonitet, users_bonitet.tstamp,
club_offer.id AS offerId, club_offer.rank
FROM users_bonitet
INNER JOIN (
SELECT max( tstamp ) AS lastDate, user_id
FROM users_bonitet
GROUP BY user_id
)lastDate ON users_bonitet.tstamp = lastDate.lastDate
AND users_bonitet.user_id = lastDate.user_id
JOIN users ON users_bonitet.user_id = users.id
JOIN club ON users.id = club.user_id
JOIN club_offer ON club.id = club_offer.club_id
JOIN club_territories ON club.id = club_territories.club_id
WHERE club_territories.territory_id = 1100000
因此,我为所有俱乐部成员(member)提供的所有俱乐部报价选择 bonitet 值,这些俱乐部成员(member)在 id 为 1100000 的领土上运营。重要的是我选择 club_offer.id AS offerId,因为我需要使用在我的应用程序代码中添加那个 offerId,这样我就可以根据为每个优惠返回的 bonitet 值进行一些计算,并将计算的数据插入到字段“club_offer.rank”中,用于 ID 为 offerId 的每一行。
最佳答案
您的查询看起来不错。我怀疑如果您添加一个复合索引来帮助子查询从 users_botinet
中为每个用户找到最新条目,您的查询性能可能会得到改善。
子查询是:
SELECT max( tstamp ) AS lastDate, user_id
FROM users_bonitet
GROUP BY user_id
如果您将(user_id, tstamp)
添加为该表的索引,则可以使用非常高效的loose index scan 来满足该子查询。 .
ALTER TABLE users_bonitet ADD KEY maxfinder (user_id, tstamp);
请注意,如果此 users_botinet
表中有一个自动递增的 ID 号,您的子查询可以重构为使用它而不是 tstamp
。这将消除重复的可能性并且效率更高,因为有一个唯一的 id 用于加入。就像这样。
FROM users_botinet
INNER JOIN (
SELECT MAX(id) AS id
FROM users_botinet
GROUP BY user_id
) ubmax ON users_botinet.id = ubmax.id
在这种情况下,您的复合索引将是 (user_id, id
。
专业提示:不要添加大量索引,除非您知道自己需要它们。阅读索引如何帮助您是个好主意。例如。 http://use-the-index-luke.com/
关于php - JOIN 查询在真实数据库上太慢,在小型数据库上运行良好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29121265/