此查询将显示给定论坛中的所有未读主题。 EXPLAIN EXTENDED
的输出有点令人担忧。我想知道这里是否有人可以提供一些有关如何优化的见解。
SELECT topic.*
FROM topic
INNER JOIN board ON topic.board_id = board.id OR topic.board_id = board.mirror_board_id
INNER JOIN category ON board.category_id = category.id
INNER JOIN group_assoc
ON (
group_assoc.board_id = board.id AND
group_assoc.group_id IN (4,15,18,22) AND
group_assoc.viewable = 1
)
WHERE topic.last_post_time > 1288278402
AND category.forum_id = 2
AND board.id NOT IN(4,3)
AND NOT EXISTS (
SELECT *
FROM topic_read_assoc
WHERE topic_id = topic.id
AND member_id = 332
)
ORDER BY topic.last_post_time DESC
输出:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY category ref PRIMARY,forum_id_2 forum_id_2 4 const 5 100.00 Using temporary; Using filesort
1 PRIMARY board ref PRIMARY,mirror_board_id,category_id_2 category_id_2 4 source_forum.category.id 4 100.00 Using where
1 PRIMARY group_assoc ref board_id,board_id_2,board_id_3 board_id_3 4 source_forum.board.id 4 100.00 Using where; Using index
1 PRIMARY topic ALL board_id_2 NULL NULL NULL 2462 100.00 Range checked for each record (index map: 0x4)
2 DEPENDENT SUBQUERY topic_read_assoc ref topic_id topic_id 8 source_forum.topic.id,const 1 100.00 Using index
答案 0 :(得分:2)
在topic (last_post_time)
上创建索引。
您也可以从LIMIT 1
子查询中删除EXISTS
,这是多余的。
答案 1 :(得分:1)
不要将EXISTS用于group_assoc表,而是在板上使用内部连接(实际上无论如何都要使用“WHERE board_id = board.id”。将过滤信息放在WHERE子句中。
对于topic_read_assoc也是如此 - 在主题ON topic_id = topic.id上使用内部联接。
另外,这只是为了让它更容易,你可以使用Board.id的IN语法,所以它只有这样一行:
WHERE ... board.id NOT IN(3,4)
编辑>正如Quassnoi在下面正确指出的那样,简单地添加内部联接将导致重复。因此,请使用您想要查看的DISTINCT或GROUP BY。顺便说一句,查询不应该使用SELECT *。如果将一列添加到该表中,您的代码可能会被破坏(不在查询本身,而是在结果中完成)。
答案 2 :(得分:0)
这将是我在论坛中显示所有未读主题的查询
select * from forum_topic where forum_id = 1 and num_views = 0;
简单示例如下:
-- TABLES
drop table if exists forum;
create table forum
(
forum_id int unsigned not null auto_increment primary key,
title varchar(255) unique not null,
num_topics int unsigned not null default 0
)engine=innodb;
drop table if exists forum_topic;
create table forum_topic
(
topic_id int unsigned not null auto_increment primary key,
forum_id int unsigned not null,
subject varchar(255) unique not null,
num_views int unsigned not null default 0,
num_replies int unsigned not null default 0,
key (forum_id)
)engine=innodb;
delimiter #
create trigger forum_topic_after_ins_trig after insert on forum_topic
for each row
begin
update forum set num_topics=num_topics+1 where forum_id = new.forum_id;
end#
delimiter ;
-- STORED PROCEDURES
drop procedure if exists get_forum_topic;
delimiter #
create procedure get_forum_topic
(
in p_topic_id int unsigned
)
begin
update forum_topic set num_views=num_views+1 where topic_id = p_topic_id;
select * from forum_topic where topic_id = p_topic_id;
end #
delimiter ;
-- TEST DATA
insert into forum (title) values ('forum1'),('forum2');
insert into forum_topic (forum_id, subject) values
(1,'forum 1 topic 1'), (1,'forum 1 topic 2'),
(2,'forum 2 topic 1'), (2,'forum 2 topic 2');
-- TESTING
call get_forum_topic(1);
call get_forum_topic(3);
call get_forum_topic(2);
call get_forum_topic(3);
call get_forum_topic(2);
call get_forum_topic(3);
select * from forum;
select * from forum_topic;
select * from forum_topic where num_views = 0;