在真正的数据库上JOIN查询太慢了,在小的一个上它运行正常

时间:2015-03-18 11:49:36

标签: php mysql database performance join

我需要帮助这个执行时间太长或根本不执行的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插入的时间。每当某些用户的bonitet值改变时,新行插入tstamp那个插入物,当然还有新的bonitet值。)所以基本上一些用户可以拥有1的bonitet,表明他处境不好,但是经过一段时间后,它可以变为3,表明他做得很好,并且该变化的时间存储在 tstamp 中。

现在,我将列出我们需要在查询中使用的其他表,然后我将解释原因。表格包括:用户分会 club_offer club_territories

有些用户(公司)是俱乐部的成员。俱乐部会员可以获得一些俱乐部优惠(他向人民和其他俱乐部会员代表他的产品),并且他在某些地区开展业务。

我需要做的是为每个俱乐部提供(由俱乐部成员的某个用户制作)获得bonitet值,但仅限于ID为110000的特定区域;由于每个用户的bonitet值随时间而变化,这意味着我只需要获得最新的。因此,如果某个用户在2012年1月21日有1的bonitet,但是后来在2012年6月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

因此,我选择俱乐部会员用户所有俱乐部优惠的bonitet值,并在id为1100000的领域进行操作。重要的是我选择了club_offer.id AS offerId,因为我需要使用在我的应用程序代码中提供了这个,所以我可以根据为每个商品返回的bonitet值进行一些计算,并为id为offerId的每一行插入计算到字段“club_offer.rank”的数据。

1 个答案:

答案 0 :(得分:2)

您的查询看起来很好。我怀疑如果你添加一个复合索引来帮助查找每个用户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/