如何改进这个嵌套的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的索引和外键
任何帮助都会非常感激。
答案 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查看如何进一步改进它。