我有两个问题要从mysql数据库中获取相关标记,一个有效,一个没有,我的问题是:“为什么?”
问题: 执行第一个查询时,mysql服务器获得100%的cpu使用率,必须重新启动才能再次运行。
查询1 (不起作用):
SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct, tags
WHERE ct.company_id IN (
SELECT ct.company_id FROM company2tag ct
WHERE ct.tag_id = 18
GROUP BY ct.company_id
HAVING COUNT(ct.company_id) = 1
)
AND tags.id != 18
AND tags.id = ct.tag_id
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;
查询2 (有效):
SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct, tags
WHERE ct.company_id IN (5864, 5870, 6140, 6221, 6268)
AND tags.id != 18
AND tags.id = ct.tag_id
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;
据我所知,上面的两个查询完全相同,唯一的区别是第一个查询通过子选择检索其“company_id”。
这怎么可能发生?
答案 0 :(得分:3)
首先,您可能遇到第一个查询的问题,因为您有两个别名为ct的表...一个在外部查询中,一个在子查询中。
其次,您可以将IN重写为JOIN:
SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct
INNER JOIN tags ON tags.id = ct.tag_id
INNER JOIN (
SELECT company_id FROM company2tag
WHERE tag_id = 18
GROUP BY company_id
HAVING COUNT(company_id) = 1
) ctf ON ct.company_id = ctf.company_id
WHERE tags.id != 18
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;
请注意,我实际上没有对此进行测试。
答案 1 :(得分:2)
MySQL
在优化IN
条件方面不是很好。
第一个查询中的条件不能轻易地重写为EXISTS
,这就是MySQL
检查每行结果的原因。
如果您想选择company_id
中多次提及的tag 18
,最好重写此查询:
SELECT tags.*, COUNT(company_id) AS count
FROM company2tag ct
JOIN tags
ON tags.id = ct.tag_id
WHERE ct.tag_id <> 18
AND NOT EXISTS
(
SELECT NULL
FROM company2tag cti
WHERE cti.tag_id = 18
AND cti.company_id = ct.company_id
LIMIT 1, 1
)
GROUP BY
ct.tag_id
ORDER BY
count DESC
这里的主要想法是你不需要COUNT(*)
:仅仅检查至少存在两个值就足够了。
在我的博客中查看类似问题的文章:
拥有以下索引:
CREATE INDEX ix_company2tag_tag_company_id ON company2tag (tag_id, company_id)
将大大改善此查询。