[英]JOIN query too slow on real database, on small one it runs fine
我需要有关执行时间太长或根本不执行的mysql查询的帮助。
(我想做的是解决更复杂的问题的一部分,我想创建一个PHP cron脚本,该脚本将执行少量繁重的查询,并根据返回的结果计算数据,然后使用这些数据将其存储在数据库中,从而更加方便使用。很可能我会在这里对这个过程提出疑问。)
首先,让我们尝试解决这些繁重查询中的一个问题。
这是东西:
我有表: users_bonitet 。 该表具有以下字段: id , user_id , bonitet , tstamp 。
第一个重要说明:当我说用户时 ,请理解用户实际上是公司 ,而不是人。 所以user.id是某家公司的ID,但是由于某些其他原因,我在这里使用的表称为“ 用户 ”。
users_bonitet表中的三个关键字段是: user_id (引用user.id ), bonitet (代表用户的强度,它可以具有3个值, 1-2-3 ,其中3是最佳值)和tstamp(存储时间)每次当某些用户更改了bonitet值时,都会插入新行,并附带该插入的tstamp以及新的bonitet值。) 因此,基本上,一些用户可以将1的bonitet表示自己处于不良状况,但一段时间后可以将其更改为3,表示他的工作状况很好,并且该更改的时间存储在tstamp中 。
现在,我将列出我们需要在查询中使用的其他表,然后解释原因。 表格为: user , club , club_offer和club_territories 。
一些用户(公司)是俱乐部的成员。 俱乐部成员可以提供一些俱乐部要约(他向人们和其他俱乐部成员展示自己的产品),并且在某些地区运营。
我需要做的是为每个俱乐部要约(由某个俱乐部成员的用户提供)获得最优惠的价格,但仅针对ID为1100000的特定区域; 由于每位用户的参数值都会随着时间而变化,这意味着我只需要获取最新的值。 因此,如果某位用户在2012年1月21日的第一位参数为bonitet,但在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
因此,我正在为ID为1100000的俱乐部会员的用户提供的所有俱乐部要约选择原始值。重要的是,我正在选择club_offer.id AS offerId,因为我需要在其中使用该offerId我的应用程序代码,这样我就可以基于为每个要约返回的原始值进行一些计算,并为要约ID为id的每一行插入计算到的字段“ club_offer.rank”。
您的查询看起来不错。 我怀疑如果添加复合索引来帮助子查询从users_botinet
查找每个用户的最新条目,则查询性能可能会得到改善。
子查询是:
SELECT max( tstamp ) AS lastDate, user_id
FROM users_bonitet
GROUP BY user_id
如果将(user_id, tstamp)
添加为该表的索引,则非常高效的松散索引扫描可以满足该子查询。
ALTER TABLE users_bonitet ADD KEY maxfinder (user_id, tstamp);
请注意,如果此users_botinet
表中具有自动递增的ID号,则可以将您的子查询重构为使用该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/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.