Mysql子选择问题

时间:2009-07-29 13:49:13

标签: sql mysql database

我有两个问题要从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”。

这怎么可能发生?

2 个答案:

答案 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)

将大大改善此查询。