我遇到以下问题的问题...需要永远加载...有时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
答案 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
引入其余日志文件的聚合。