将3个查询优化为一个

时间:2014-06-28 18:16:20

标签: php mysql sql

我只想弄清楚如何将以下查询序列优化为单个查询。

具体来说,下面的查询就像在用户登录帐户时向用户显示的警报。

$sq = "SELECT COUNT(*) as totm FROM login as l 
       JOIN msgs m on m.id = l.id 
       WHERE m.tstamp > l.mtstamp AND l.id = $id;";

$sq .= "SELECT COUNT(*) as totp FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 0 AND u.id = $id;";

$sq .= "SELECT COUNT(*) as totq FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 1 AND u.id = $id";

现在我使用mysqli_multi_query()来运行这多个查询。 但是我已经设法将其缩减为单个查询

$sq = "SELECT m.totm,p.totp FROM login as l 
       JOIN info as u on u.id = l.id
       LEFT JOIN (SELECT tstamp,id,COUNT(*) as 'totm' FROM msgs GROUP BY id) m 
       ON m.id = l.id AND m.tstamp > l.mtstamp
       LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst 
                  GROUP BY id) p 
       ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 0 
       AND p.id <> l.id WHERE l.id = $id 
       LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst 
                  GROUP BY id) p 
       ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 1 
       AND p.id <> l.id WHERE l.id = $id LIMIT 1";

当我使用EXPLAIN STATEMENT尝试单个查询时,查询输出太差,很多行都会受到影响。

当我在三个查询中单独执行相同操作时,结果很好。我不确定我应该运行多个查询还是尝试单个查询。

在谷歌搜索后,我发现groupBY会导致连接和许多行的严重开销。好的,任何人都让我知道什么是更好的方法来解决这个问题。任何人都可以帮我写一个更优化的查询。谢谢。任何帮助是极大的赞赏。

1 个答案:

答案 0 :(得分:1)

如果您尝试检索特定ID的计数,那么我建议您将查询组合为select中的子查询。使用GROUP BY没有任何意义,因为您正在查找特定ID的计数。

SELECT
(SELECT COUNT(*) FROM login as l 
       JOIN msgs m on m.id = l.id 
       WHERE m.tstamp > l.mtstamp AND l.id = $id) totm,
(SELECT COUNT(*) FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 0 AND u.id = $id) totp,
(SELECT COUNT(*) FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 1 AND u.id = $id) totq

将此与检索每个ID的计数进行对比,在这种情况下,GROUP BY上的id会很有用:

SELECT t1.id,t1.totm,t2.totp,t3.totq
FROM
(SELECT l.id, COUNT(*) as totm FROM login as l 
       JOIN msgs m on m.id = l.id 
       WHERE m.tstamp > l.mtstamp
       GROUP BY l.id) t1
LEFT JOIN (SELECT u.id, COUNT(*) as totp FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 0 
        GROUP BY u.id) t2 ON t1.id = t2.id
LEFT JOIN (SELECT u.id, COUNT(*) as totq FROM info as u 
        JOIN pst as p on p.cid =  u.cid
        JOIN login as l on l.id = u.id 
        WHERE p.tstamp > l.ptstamp AND p.id <> u.id 
        AND p.type = 1
        GROUP BY u.id) t3 ON t2.id = t3.id