Как оптимизировать получение related'ов к книге по авторам, тэгам?

Крот

Новичок
Как оптимизировать получение related'ов к книге по авторам, тэгам?

Привет. У меня возник небольшой затык...

Итак, есть сущность - книга. Книге сопоставляются тэги, для этого сделана таблица (тип myisam).

tags2books
tag_id INT INDEX
book_id INT INDEX

Для получения "релейтедов" выполняю вот такие запросы
SELECT book_id FROM tags2books WHERE tag_id IN (SELECT tag_id FROM tags2books WHERE book_id = '5862') AND book_id != '5862';

Очень смущает вот такая запись в логе медленных запросов мускуля.
# Query_time: 0 Lock_time: 0 Rows_sent: 321 Rows_examined: 20789
SELECT book_id FROM tags2books WHERE tag_id IN (SELECT tag_id FROM tags2books WHERE book_id = '5862') AND book_id != '5862';
А именно - смущает кол-во rows examined.

Подскажите пожалуйста, как можно уменьшить это число и тем самым ускорить запрос?

Поля сделаны индексами, т.е. без индексов вообще нереальное кол-во rows examined было. :)

Мои мысли: Может быть стоит отказаться от оператора IN в пользу цикла с менее затратными запросами? Это еще вдобавок позволит сделать настоящий релейтед, а не какой-то "рандом". Под настоящим релейтедом я понимаю - сперва получаение книг, у которых все тэги совпадают, потом совпает n-1 тэг и т.д.

Очень хотелось бы услышать мнения.

Спасибо!

-~{}~ 20.10.09 17:37:

Или может быть вообще есть какой-то более рациональный способ получения\организации related'ов.
 

Beavis

Banned
ты можешь по русски объяснить что у тебя есть и что тебе нужно получить? визаут "релейтед" етц
 

Krishna

Продался Java
Beavis
[telepate_mode]Ну судя по запросу, он получает список книг, в которых есть те же теги, что и в текущей.[/telepate_mode]
 

Крот

Новичок
Да, прощу прощения.

Я просто получаю список книг аналогичной тематики, т.е. выбираю книги, у которых есть похожие тэги.

-~{}~ 20.10.09 17:56:

Автор оригинала: Krishna
Вместо вложенного запроса с IN используй JOIN.
Спасибо, сейчас же попробую. О результатах отпишусь.
 

Beavis

Banned
главное чтоб щас не получилось вот так
[SQL]
SELECT book_id FROM tags2books WHERE tag_id JOIN (SELECT tag_id FROM tags2books WHERE book_id = '5862') AND book_id != '5862';
[/SQL]
:D
 

Крот

Новичок
Автор оригинала: Beavis
главное чтоб щас не получилось вот так
[SQL]
SELECT book_id FROM tags2books WHERE tag_id JOIN (SELECT tag_id FROM tags2books WHERE book_id = '5862') AND book_id != '5862';
[/SQL]
:D
Хм, ну я именно так и сделал.

Только немного по-другому, но смысл тот же...
[SQL]
SELECT
t1.book_id
FROM
tags2books as t1,
(SELECT tag_id FROM tags2books WHERE book_id = 5862) as t2
WHERE
t1.tag_id = t2.tag_id AND
t1.book_id != 5862
[/SQL]

А как правильно? Видимо я не очень понял, что Krishna имела ввиду...
 

Krishna

Продался Java
Кришна имело ввиду вообще без вложенных запросов.
Пофантазируй немного :)
 

Крот

Новичок
:) Не знал что так можно...
Спасибо!

[SQL]
SELECT
t1.book_id
FROM
tags2books as t1,
tags2books as t2
WHERE
t1.tag_id = t2.tag_id AND
t2.book_id = 5862 AND
t1.book_id != 5862
[/SQL]

Осталось выяснить - как это на производительности скажется.
Сейчас потестирую и отпишусь.

-~{}~ 20.10.09 19:28:

Отчет

# Query_time: 0 Lock_time: 0 Rows_sent: 321 Rows_examined: 3
Только не могу понять как это так. Всего 3 строки просмотрено, а вернул 321. :) И еще непонятно - повлияло ли это как-то на производительность или нет.
 

Крот

Новичок
Да, наверное придется нагенерить пару сумасшедших таблиц, чтобы проверить время выполнения на реально большом кол-ве тэгов, т.к. сейчас за тысячные доли секунд выполняются запрос (что изначальный, что тот, который подсказали).

Насчет EXPLAIN'а - спасибо огромное. Буду сейчас изучать. Просто я с MySQL почти не знаком - очень много нового узнаю каждый день (особенно, когда начали возникать вопросы оптимизации и т.д.).
 

Krishna

Продался Java
Да, наверное придется нагенерить пару сумасшедших таблиц, чтобы проверить время выполнения на реально большом кол-ве тэгов, т.к. сейчас за тысячные доли секунд выполняются запрос (что изначальный, что тот, который подсказали).
Тогда надо сначала разобраться почему он попал в slow query log и действительно ли он должен был туда попасть.
Оптимизировать нужно только тогда, когда это становится необходимым.
Код не обязан быть максимально эффективен на 100%.

Он должен удовлетворять текущим требованиям по функциональности, производительности и при этом разрабатываться с минимальными затратами труда + в случае необходимости быть спроектирован так, чтобы в него было максимально легко вносить изменения, в частности прежде всего иметь хорошо читаемый вид.

Хотя, конечно, чисто с целью обучения можно и пооптимизировать запросы без особой на то нужды.
 

Крот

Новичок
Честно говоря, я не знаю почему он по-прежнему попадает в лог медленных запросов. Query time 0, кол-во examined rows предельно низкое (меньше чем min_examined_row_limit), время на lock и т.д. вообще отсутствует. Может быть запрос попадает из-за того, что кол-во возвращаемых строк больше определенного? Хотя, судя по http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html - кол-во возвращаемых строк не является поводом для попадания в лог медленных запросов...

-~{}~ 21.10.09 12:32:

Кстати, если нагрузка на сервер больше 1, то возможно этот запрос может попадать туда из-за отложенности?
 
Сверху