简体   繁体   中英

Optimizing simple query

This query will show you all of the unread topics in a given forum. The output of EXPLAIN EXTENDED was a bit alarming. I'm wondering if someone here can provide some insight into how I can optimize.

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

output:

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

Create an index on topic (last_post_time) .

You can also remove LIMIT 1 from the EXISTS subquery, it's redundant.

Rather than use EXISTS for the group_assoc table, use an inner join on board for it (which is in effect happening anyway with "WHERE board_id = board.id". Put the filtering info. in the WHERE clause.

The same goes for topic_read_assoc - use an inner join on topic ON topic_id = topic.id.

Also, this is just to make it easier, you can use the IN syntax for Board.id so it's only one line like this:

WHERE ... board.id NOT IN (3,4)

EDIT> As Quassnoi rightly pointed out below, simply adding inner joins will cause duplicates. So use DISTINCT or GROUP BY what you want to see. The query should not be using SELECT * anyway by the way. If a column is added to that table, your code could be broken (not in the query itself, but by what is done with the results).

this would be my query for showing all unread topics in a forum

select * from forum_topic where forum_id = 1 and num_views = 0;

simple example follows:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM