我一直在研究这个问题几个小时,我提出的最好的代码就是我在一个问题上发现的一个例子。我经历了几个派生,但以下是唯一返回正确数据的查询,问题是只返回139行(超过2分钟)才能返回30行数据。我卡住了。 (life_p是'喜欢'
SELECT
logos.id,
logos.in_gallery,
logos.active,
logos.pubpriv,
logos.logo_name,
logos.logo_image,
coalesce(cc.Count, 0) as CommentCount,
coalesce(lc.Count, 0) as LikeCount
FROM logos
left outer join(
select comments.logo_id, count( * ) as Count from comments group by comments.logo_id
) cc on cc.logo_id = logos.id
left outer join(
select life_p.logo_id, count( * ) as Count from life_p group by life_p.logo_id
) lc on lc.logo_id = logos.id
WHERE logos.active = '1'
AND logos.pubpriv = '0'
GROUP BY logos.id
ORDER BY logos.in_gallery desc
LIMIT 0, 30
我不确定这是错的。如果我这样做,那么意味着要删除coalece和其中一个连接:
SELECT
logos.id,
logos.in_gallery,
logos.active,
logos.pubpriv,
logos.logo_name,
logos.logo_image,
count( * ) as lc
FROM logos
left join life_p on life_p.logo_id = logos.id
WHERE logos.active = '1'
AND logos.pubpriv = '0'
GROUP BY logos.id
ORDER BY logos.in_gallery desc
LIMIT 0, 30
运行时间不到半秒(2-300毫秒)....
以下是解释的链接:https://logopond.com/img/explain.png
答案 0 :(得分:2)
MySQL有一个特殊的怪癖,它允许group by子句不列出所有非聚合列。这不是一件好事,您应该始终在group by子句中指定所有非聚合列。
注意,当计算连接表时,知道COUNT()函数忽略NULL是很有用的,因此对于可能发生NULL的LEFT JOIN,不要使用COUNT(*),而是使用内部的列联接表,只计算该表中的行。从这些点我建议以下查询结构。
SELECT
logos.id
, logos.in_gallery
, logos.active
, logos.pubpriv
, logos.logo_name
, logos.logo_image
, COALESCE(COUNT(cc.logo_id), 0) AS CommentCount
, COALESCE(COUNT(lc.logo_id), 0) AS LikeCount
FROM logos
LEFT OUTER JOIN comments cc ON cc.logo_id = logos.id
LEFT OUTER JOIN life_p lc ON lc.logo_id = logos.id
WHERE logos.active = '1'
AND logos.pubpriv = '0'
GROUP BY
logos.id
, logos.in_gallery
, logos.active
, logos.pubpriv
, logos.logo_name
, logos.logo_image
ORDER BY logos.in_gallery DESC
LIMIT 0, 30
如果您仍然遇到性能问题,请使用执行计划并考虑添加适合的索引。
答案 1 :(得分:1)
您可以在加入字段上创建一些索引:
ALTER TABLE table
ADD INDEX idx__tableName__fieldName
(field
)
在你的情况下将是:
ALTER TABLE cc ADD INDEX idx__cc__logo_id(logo_id);
答案 2 :(得分:0)
我真的不喜欢它,因为我总是读到子查询很糟糕,并且连接在压力下表现更好,但在这种特殊情况下,子查询似乎是在半秒内持续提取正确数据的唯一方法。感谢大家的建议。
SELECT
logos.id,
logos.in_gallery,
logos.active,
logos.pubpriv,
logos.logo_name,
logos.logo_image,
(Select COUNT(comments.logo_id) FROM comments
WHERE comments.logo_id = logos.id) AS coms,
(Select COUNT(life_p.logo_id) FROM life_p
WHERE life_p.logo_id = logos.id) AS floats
FROM logos
WHERE logos.active = '1' AND logos.pubpriv = '0'
ORDER BY logos.in_gallery desc
LIMIT ". $start .",". $pageSize ."
答案 3 :(得分:0)
您还可以创建映射表以加快查询速度:
CREATE TABLE mapping_comments AS
SELECT
comments.logo_id,
count(*) AS Count
FROM
comments
GROUP BY
comments.logo_id
) cc ON cc.logo_id = logos.id
然后更改您的代码
left outer join(
应该成为
inner join mapping_comments as mp on mp.logo_id =cc.id
然后,每次向cc表添加新注释时,您需要更新映射表,或者您可以创建存储过程以在cc表更改时自动执行