如何改进这个嵌套的select语句

时间:2013-05-13 00:13:18

标签: mysql

如何改进这个嵌套的select语句,因为我认为它的性能很差,因为我认为它需要很长时间才能执行并且服务器负载很高

SELECT user_tagtag,
user_lastcontentid,
(SELECT COUNT( content_id )  
 FROM contents 
 WHERE contents.content_id > user_lastcontentid AND 
       contents.content_id IN ( 
         SELECT contenttag_contentid 
         FROM contents_vs_tags 
         WHERE contenttag_tagtag = user_tagtag 
       ) 
) AS tag_newnews_no
FROM users_interests_tags  
WHERE user_userid = 1 
ORDER BY user_tagsorder ASC

users_interests_tags表结构是:

+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| user_userid        | bigint(20)   | NO   | PRI | NULL    |       |
| user_tagtag        | varchar(255) | NO   | PRI | NULL    |       |
| user_lastcontentid | bigint(20)   | YES  | MUL | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+

内容表结构是:

+---------------------+----------------+------+-----+---------+----------------+
| Field               | Type           | Null | Key | Default | Extra          |
+---------------------+----------------+------+-----+---------+----------------+
| content_id          | bigint(20)     | NO   | PRI | NULL    | auto_increment |
| content_title       | varchar(255)   | NO   | MUL | NULL    |                |
+---------------------+----------------+------+-----+---------+----------------+

contents_vs_tags表结构是:

+----------------------+--------------+------+-----+---------+-------+
| Field                | Type         | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| contenttag_contentid | bigint(20)   | NO   | PRI | NULL    |       |
| contenttag_tagtag    | varchar(255) | NO   | PRI | NULL    |       |
+----------------------+--------------+------+-----+---------+-------+

其中contents_vs_tags.contenttag_contentid是contents.content_id的索引和外键

任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:3)

通常,相关子查询(必须为每一行执行,因此导致巨大的性能问题)可以转换为连接,并且您的查询属于此类别:

SELECT
    user_tagtag,
    user_lastcontentid,
    COUNT( distinct content_id ) AS tag_newnews_no
FROM users_interests_tags
LEFT JOIN contents_vs_tags ON contenttag_tagtag = user_tagtag
LEFT JOIN contents ON contents.content_id = contenttag_contentid
WHERE user_userid = 1
AND contents.content_id > user_lastcontentid
GROUP BY 1, 2
ORDER BY user_tagsorder

通过使用LEFT JOIN,仍然会返回没有匹配行的标签,但是它们的计数为零。

请注意使用distinct来获取您的查询返回的相同结果。

这将比你的查询更好地执行 (并且明显优于其他答案!)因为所有访问都是直接来自tsbles,而不是通过子查询。

确保键列上有索引:

CREATE INDEX contents_vs_tags_1 ON contents_vs_tags(contenttag_tagtag);
CREATE INDEX contents_1 ON contents(content_id);

答案 1 :(得分:0)

您应该为代码创建索引。

CREATE INDEX `idx_tag` ON users_interests_tags (user_tagtag(10));

以及

CREATE INDEX `idx_tag` ON contents_vs_tags (contenttag_tagtag(10));

查询:

SELECT t1.user_tagtag, t1.user_lastcontentid,
    (
        SELECT COUNT( t2.content_id )  
        FROM contents t2
        INNER JOIN contents_vs_tags t3 ON (t3.contenttag_tagtag = t1.user_tagtag)
        WHERE t2.content_id > t1.user_lastcontentid 
            AND t3.contenttag_tagtag = t1.user_tagtag 
    ) AS tag_newnews_no
FROM users_interests_tags t1
WHERE t1.user_userid = 1 
ORDER BY t1.user_tagsorder ASC

一旦未对列进行索引,您的ORDER BY可能仍会出现问题。它可以为您提供临时表和文件排序。

密切注意并使用EXPLAIN查看如何进一步改进它。