优化简单查询

时间:2010-11-11 21:31:18

标签: mysql optimization

此查询将显示给定论坛中的所有未读主题。 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

3 个答案:

答案 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;