Тормозящий запрос в IPB

BRat

o_0
Тормозящий запрос в IPB

Есть в IPB такая штука как экспорт RSS. Запрос такой -

[sql]
SELECT p.*, t.tid, t.title as topic_title, t.starter_name as topic_starter_name, t.forum_id FROM inv_posts p, inv_topics t WHERE p.topic_id = t.tid AND t.forum_id IN( 40 ) AND t.state != "link" AND t.approved=1 ORDER BY p.pid desc LIMIT 0,10;
[/sql]
Запрос на 200 000 постах и 200 топиках выполняется около 10 секунд

EXPLAIN:
Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	SIMPLE 	t 	ref 	PRIMARY,forum_id,last_post,state,approved,forum_id... 	forum_id_state_approved 	2 	const 	175 	Using where; Using temporary; Using filesort
1 	SIMPLE 	p 	ref 	topic_id 	topic_id 	4 	u24710_forum.t.tid 	36
При ловле проблемы довел запрос до такого вида -
[sql]
SELECT * FROM inv_posts p
LEFT JOIN inv_topics t
ON p.topic_id=t.tid
WHERE t.forum_id = 40
ORDER BY p.pid desc LIMIT 0,10;
[/sql]

Если убрать условие WHERE - тормозить перестает (0,02 сек). Если оставить WHERE и убрать ORDER - тоже не тормозит.

Запрос я конечно переразобью на два, чтобы не было джойна, но кто-нибудь может меня просветить, почему происходит то, что происходит? Почему тормозит?
 

BRat

o_0
без сортировки
Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	SIMPLE 	t 	ref 	PRIMARY,forum_id,last_post,forum_id_state_approved 	last_post 	2 	const 	491 	Using where
1 	SIMPLE 	p 	ref 	topic_id 	topic_id 	4 	u24710_forum.t.tid 	36
без where

Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	SIMPLE 	p 	index 	NULL 	PRIMARY 	4 	NULL 	262083 	 
1 	SIMPLE 	t 	eq_ref 	PRIMARY 	PRIMARY 	4 	u24710_forum.p.topic_id 	1
C обоими

Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	SIMPLE 	t 	ref 	PRIMARY,forum_id,last_post,forum_id_state_approved 	last_post 	2 	const 	491 	Using where; Using temporary; Using filesort
1 	SIMPLE 	p 	ref 	topic_id 	topic_id 	4 	u24710_forum.t.tid 	36
 

antson

Новичок
Партнер клуба
Если условия переставить так сколько будет время исполнения ?

SELECT t.tid, t.title AS topic_title, t.starter_name AS topic_starter_name, t.forum_id , p . *
FROM inv_topics t,inv_posts p
WHERE t.forum_id IN ( 40 ) AND t.state != "link" AND t.approved = 1

AND t.tid = p.topic_id

ORDER BY p.pid DESC
LIMIT 0 , 10;
 

Glazyrin Sergey

Новичок
А есть ли у тебя индекс на p.pid ?
Я так понимаю нет. В данном случае может помочь. Но дело в том, что в уже существующий проект опасно добавлять индексы на таблицы. Так как могут в другом месте вылезти проблемы
 

Gas

может по одной?
А есть ли у тебя индекс на p.pid ?
по эксплейну видно что есть.

BRat
Запрос я конечно переразобью на два
попробуй сначала заменить тормозящий
Код:
SELECT * 
FROM inv_posts p
LEFT JOIN inv_topics t ON p.topic_id = t.tid
WHERE t.forum_id = 40
ORDER BY p.pid DESC 
LIMIT 0 , 10;
на
Код:
SELECT *
FROM 
(
  SELECT * 
  FROM inv_posts
  ORDER BY pid DESC 
  LIMIT 0, 10
) AS p
LEFT JOIN inv_topics t ON p.topic_id = t.tid
WHERE t.forum_id = 40
ORDER BY p.pid DESC
 

BRat

o_0
Gas
хм, работает. Показывает 8 записей. Я правильно понимаю, что тут берется сначала 10 записей с конца таблицы posts, затем они склеиваются с topics и отсеивается лишнее через WHERE ?
 

Gas

может по одной?
а, стоп, да мой запрос по логике не подходит, можно конечно в подзапросе выбирать больше постов - но это совсем не гарантирует что в итоге будет нужное количество записей.
 

BRat

o_0
да, это видимо с 40ым форумом повезло, в нем чаще других пишут
 

Gas

может по одной?
а если попробовать так:
Код:
SELECT p . * , t.tid, t.title AS topic_title, t.starter_name AS topic_starter_name, t.forum_id
FROM inv_posts p
JOIN (
  SELECT * 
  FROM inv_topics
  WHERE forum_id IN ( 40 ) AND state != "link" AND approved = 1
) AS t ON p.topic_id = t.tid
ORDER BY p.pid
только желательно сначала:
ALTER TABLE inv_posts ADD INDEX topic_post(topic_id, pid);
Eсли при джойне первой таблицей будет идти `t` - то поставть LEFT join или FORCE INDEX (topic_post)

Если тоже будет тормоз - кинь его explain
 

BRat

o_0
Там уже был такой индекс "topic_id_pid". Тормозят оба запроса

исходный EXPLAIN

Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	PRIMARY 	<derived2> 	ALL 	NULL 	NULL 	NULL 	NULL 	529 	Using temporary; Using filesort
1 	PRIMARY 	p 	ref 	topic_id,topic_id_pid 	topic_id 	4 	t.tid 	36 	 
2 	DERIVED 	inv_topics 	ref 	forum_id,last_post,state,approved,forum_id_state_a... 	forum_id_state_approved 	2 	  	175 	Using where
С LEFT JOIN

Код:
1  	PRIMARY  	p  	ALL  	NULL  	NULL  	NULL  	NULL  	262216  	Using temporary; Using filesort
1 	PRIMARY 	<derived2> 	ALL 	NULL 	NULL 	NULL 	NULL 	529 	 
2 	DERIVED 	inv_topics 	ref 	forum_id,last_post,state,approved,forum_id_state_a... 	forum_id_state_approved 	2 	  	175 	Using where
Подскажи плз, в какое место запроса FORCE INDEX прописать ?
 

Gas

может по одной?
FROM inv_posts p FORCE INDEX (pid)
и попробуй потом вместо pid прописать topic_id_pid
тестируй пока с left join'ом, чтоб точно знать что inv_posts была первой при объединении.

кстати, а эти эксплейны точно с limit'ом ? я у себя забыл указать.
 

BRat

o_0
Gas
Да, перепроверил, с лимитом

[sql]
SELECT p. * , t.tid, t.title AS topic_title, t.starter_name AS topic_starter_name, t.forum_id
FROM inv_posts p FORCE INDEX ( topic_id_pid )
LEFT JOIN (
SELECT *
FROM inv_topics
WHERE forum_id
IN ( 40 )
AND state != "link"
AND approved =1
) AS t ON p.topic_id = t.tid
ORDER BY p.pid DESC
LIMIT 0 , 10
[/sql]

EXPLAIN такой же как в примере LEFT JOINа выше

тег sql неправильно слово force парсит )
 

nalim

Новичок
Все дело в том что даже если ключи есть
и у MySQL вроде и нет причин пробегать всю таблицу
изза ORDER BY + JOIN он всеравно будет это делать...
ну вот алергия у него и всё тут)
 

BRat

o_0
nalim
да, x-yuri почти в начале топика дал ссылку на эту аллергию
 
Сверху