2009-07-29 78 views
1

我有两个查询从一个mysql数据库得到相关标签,一个工作,一个没有,我的问题是:“为什么?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

子查询又是如何进行的? – paxdiablo 2009-07-29 13:53:46

+0

完美地工作,它返回company_id的列表。 – smoove 2009-07-29 13:54:44

回答

3

首先,您可能会遇到第一个查询中的问题,因为您有两个表会被别名为ct ...其中一个在外部查询中,一个在子查询中。

其次,你可以重写作为一个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; 

请注意,我并没有实际测试过这一点。

2

MySQL在优化IN条件中不是很好。

您的第一个查询中的条件不能轻易重写为EXISTS,这就是为什么MySQL会检查每行的结果。

如果你想选择在tag 18不止一次提到company_id的,这是更好地重写此查询这样:

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) 

将大大提高此查询。