Тормозит вложенный запрос...

sergasd

Новичок
Делаю простенький форум.
Таблицы:
users
user_id | user_name | register_date

topics
topic_id | user_id | topic_title | topic_date

posts
post_id | topic_id | user_id | post_text | post_date

На главной странице необходимо вывести список тем, авторов тем, время и автора последнего сообщения в теме. Написал запрос (ниже). При небольшом числе постов работает довольно быстро, для экспиримента вставил в таблицу постов 200000 записей и запрос начал выполняться ~1.5 сек. Как его можно оптимизировать?

PHP:
SELECT TITLE, ID, AUTOR, COUNT, LAST_POST, posts.post_date, users.user_name
FROM posts JOIN users USING(user_id)
JOIN
(
SELECT topics.topic_title AS TITLE, topics.topic_id AS ID, users.user_name AS AUTOR,
COUNT( posts.post_id ) AS COUNT, MAX( posts.post_id ) AS LAST_POST
FROM topics
JOIN posts
USING ( topic_id )
JOIN users ON users.user_id = topics.user_id
GROUP BY topics.topic_title
)
AS tbl ON posts.post_id = LAST_POST
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Ну хрен знает, данных ты привел маловато. Ни самих дампов таблиц не выложил, ни create table ни explain...
 

sergasd

Новичок
EXPLAIN
http://img218.imageshack.us/i/explainn.jpg/

--
-- Структура таблицы `posts`
--

CREATE TABLE `posts` (
`post_id` int(10) unsigned NOT NULL auto_increment,
`topic_id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`post_text` text NOT NULL,
`post_date` datetime NOT NULL,
PRIMARY KEY (`post_id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=218734 ;

-- --------------------------------------------------------

--
-- Структура таблицы `topics`
--

CREATE TABLE `topics` (
`topic_id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL,
`topic_title` varchar(300) NOT NULL,
`topic_date` datetime NOT NULL,
PRIMARY KEY (`topic_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=12 ;

-- --------------------------------------------------------

--
-- Структура таблицы `users`
--

CREATE TABLE `users` (
`user_id` int(10) unsigned NOT NULL auto_increment,
`user_name` varchar(200) NOT NULL,
`register_date` date NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=30033 ;
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
37k строк в последнем ряде эксплейна говорят о многом) Ну в общем я так понял что ты хочешь вытянуть все в 1 запрос, типа тему, сколько там мессаг в ней, кто писал и т.д.

Если не впадлу выкинь дамп sql-ный куда-нить на rghost я тогда помучаю запрос как время будет, так я не гуру писать на лету. Но джоин селекта как-то не йас имхо.
 

sergasd

Новичок
Вот ссылка, благодарю за помощь.
В одном запросе или двух это непринципиально, главное чтобы не тормозил запрос) и в php таблица в удобном виде пришла.
 

Gas

может по одной?
sergasd
чтоб такая логика быстро работала - вводится денормализация: значения count() и last_id добавляются в таблицу topics. Пересчёт можно повесить на тригеры.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Угу, это верно. Тоже хотел предложить ему это

Я JOIN заменил бы на вложенный селект, у меня почему-то первый JOIN для определения количества постов отрабатывал за 0.6-0.7 секунды, а аналог с вложенным SELECT 0.35 секунды. Потому вышло что-то вроде этого:

SELECT SQL_NO_CACHE (SELECT COUNT(post_id) FROM posts p WHERE p.topic_id=t.topic_id) as post_count, (SELECT user_name from users u WHERE u.user_id = t.user_id) as user_name, (SELECT CONCAT_WS('_', MAX(post_id), post_text) FROM posts p WHERE p.topic_id=t.topic_id) as max_post_data, t.topic_id, t.user_id, t.topic_title, t.topic_date FROM topics t;

выполняется за 0.6 секунды на моем ноуте.
 

sergasd

Новичок
Видимо придется денормализацию делать, спасибо за советы.
 
Сверху