左连接查询永远执行

时间:2014-06-20 23:17:23

标签: mysql sql innodb

我遇到以下问题的问题...需要永远加载...有时10秒,其他70秒,这对我来说似乎很疯狂。

我正在做的是抓住各种活动/表的计数。我已经读过我不应该把条件放在ON子句中,因为这些是外连接,但是,如果我不把它们放在WHERE中那么我最终没有结果......这是有道理的对于整个整体而言,我需要每个联接的结果。

话虽如此,为什么世界上这个查询需要太长时间?该计划似乎正常运作。整个数据库只有700KiB,但这个查询总是写入磁盘,有时tmp文件大小超过10gig ......这怎么可能?根据计划,我正在得到我所需要的,几乎没有任何行/信息。

使用innodb作为数据库。

任何帮助都会非常感激,因为目前这个问题对我来说毫无意义。

SELECT
  users.user_id as DT_RowId,
  users.username as username,
  computers.computer_name as computer_name,
  count(distinct log1.activity_id) as log1s,
  count(distinct log2.activity_id) as log2s,
  count(distinct log3.activity_id) as log3s,
  count(distinct log4.activity_id) as log4s,
  count(distinct log5.activity_id) as log5s,
  count(distinct log6.activity_id) as log6s,
  count(distinct log7.activity_id) as log7s,
  count(distinct log8.activity_id) as log8s,
  count(distinct log9.activity_id) as log9s,
  count(distinct log10.activity_id) as log10s,
  count(distinct log11.activity_id) as log11s

FROM computers

INNER JOIN users
    on users.computer_id = computers.computer_id

LEFT JOIN log1
    on log1.user_id = users.user_id

LEFT JOIN log2
    on log2.user_id = users.user_id

LEFT JOIN log3
    on log3.user_id = users.user_id

LEFT JOIN log4
    on log4.user_id = users.user_id

LEFT JOIN log5
    on log5.user_id = users.user_id

LEFT JOIN realtime_logs AS log6
    on log6.user_id = users.user_id AND log6.event_title = 'test1'

LEFT JOIN realtime_logs AS log7
    on log7.user_id = users.user_id AND log7.event_title = 'test2'

LEFT JOIN realtime_logs AS log8
    on log8.user_id = users.user_id AND log8.event_title = 'test3'

LEFT JOIN realtime_logs AS log9
    on log9.user_id = users.user_id AND log9.event_title = 'test4'

LEFT JOIN realtime_logs AS log10
    on log10.user_id = users.user_id AND log10.event_title = 'test5'

LEFT JOIN realtime_logs AS log11
    on log11.user_id = users.user_id AND log11.event_title = 'test6'

WHERE computers.account_id = :cw_account_id AND computers.status = :cw_status

GROUP BY users.user_id

计划:

computers   1   SIMPLE  ref PRIMARY,unique_filter,status    unique_filter   4   const   5   Using where; Using temporary; Using filesort
users   1   SIMPLE  ref unique_filter   unique_filter   4   stephen_inno.computers.computer_id  1   Using index
log1    1   SIMPLE  ref user_id user_id 4   stephen_inno.users.user_id  1   Using index
log2    1   SIMPLE  ref user_id user_id 4   stephen_inno.users.user_id  1   Using index
log3    1   SIMPLE  ref user_id user_id 4   stephen_inno.users.user_id  1   Using index
log4    1   SIMPLE  ref user_id user_id 4   stephen_inno.users.user_id  1   Using index
log5    1   SIMPLE  ref user_id user_id 4   stephen_inno.users.user_id  1   Using index
log6    1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index
log7    1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index
log8    1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index
log9    1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index
log10   1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index
log11   1   SIMPLE  ref user_id user_id 771 stephen_inno.users.user_id,const    3   Using index

编辑:

使用下面的Gordon's解决方案。我必须说现在它的运行速度非常快,但是,我确实看到计划中有些东西引起了人们的注意。以下是其中一个左连接表的计划:

<derived2>  1   PRIMARY ALL                 7   
log5    2   DERIVED index       user_id 775     1304    Using index

派生的类型为&#39; all&#39;并读取7行。子查询具有一种索引并读取1304行。 1304是此数据库中的总行数...无论它是否属于此查询 - WHERE computers.account_id = :cw_account_id AND computers.status = :cw_status。所以看起来这不会起作用,除非我读错了......我当然不想为每一个读取整个数据库。

想法?

编辑2:

关于扫描整个表以获取这些连接的问题,我想我可以在我的from中使用子查询然后加入到那个。我的思考过程是这个子查询的结果将只包含我在结果中想要的用户...因此,连接只会加入这组用户。不幸的是,在查看计划后,优化器仍在读取连接表中的每一行,而不是只加入active_users集。

想法?

  FROM
    (SELECT
        user_id,
        computer_name,
        username
      FROM computers

        INNER JOIN users
            on users.computer_id = computers.computer_id

      WHERE computers.account_id = :cw_account_id AND computers.status = :cw_status
    ) AS active_users

    ... the left join subqueries (Gordon's answer) follow joining on active_users.user_id

1 个答案:

答案 0 :(得分:1)

您正在加入多个维度,即为每个user_id创建一个笛卡尔积。编写此查询的更好方法是:

SELECT u.user_id as DT_RowId, u.username as username, c.computer_name as computer_name,
       l1.cnt as log1s,
       l2.cnt as log2s,
       . . .
FROM computers c INNER JOIN
     users u
     on u.computer_id = c.computer_id LEFT JOIN
     (select user_id, count(*) as cnt
      from log1
      group by user_id
     ) l1
     on l1.user_id = u.user_id LEFT JOIN
     (select user_id, count(*) as cnt
      from log2
      group by user_id
     ) l2
     on l2.user_id = u.user_id
     . . .

继续使用left join引入其余日志文件的聚合。