1

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

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_contentidcontent.content_id的索引和外键在哪里

任何帮助将非常感激。

4

2 回答 2

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,而不是通过子查询 thsn。

确保您在键列上有索引:

CREATE INDEX contents_vs_tags_1 ON contents_vs_tags(contenttag_tagtag);
CREATE INDEX contents_1 ON contents(content_id);
于 2013-05-13T00:45:52.670 回答
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 来检查如何进一步改进它。

于 2013-05-13T00:32:14.823 回答