Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет mumuntu ([info]mumuntu)
@ 2010-09-07 13:41:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Простенькая задачка
Дано: MySQL
В нем есть таблица блогозаписей, таблица тегов и таблица связей тег-запись, т.е., ситуация более-менее стандартная.
Требуется: написать запрос(ы), выбирающий 100 первых блогозаписей по тегам "кровь", "любовь", "морковь", "свекровь", отсортированных в порядке написания блогозаписи.
Прежде чем писать в комментарии ответы, посмотрите, пожалуйста, план вашего запроса.
UPD: планы и сами запросы кидайте в комментарии к записи, обсудим.


(Читать комментарии) - (Добавить комментарий)


[info]metaclass@lj
2010-09-07 06:36 (ссылка)
select first 100 * from posts
where exists
(select 1 from tags
join posttags on posttags.tag_id=tags.tag_id and posttags.post_id=posts.post_id
where tags.tag_value in ('черви','жабы','змеи')
)
order by blogpost_dt

MySQL нету, подходящей по размеру базы тоже, план проверить не на чем.

Если план будет очень хреновый, с бы таки сначала выбрал по значениям тэгов список их id, а затем уже его использовал в запросе, не трогая таблицу tags

(Ответить) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-07 06:39 (ссылка)
О, отлично, сейчас буду проверять, очень может быть, что это ОНО.

> Если план будет очень хреновый, с бы таки сначала выбрал по значениям тэгов список их id, а затем уже его использовал в запросе, не трогая таблицу tags

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

(Ответить) (Уровень выше)


[info]m_a_m_o_n@lj
2010-09-07 06:53 (ссылка)
Сомневаюсь что это будет работать для mysql, он не любит подзапросы, это не постгрис.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]metaclass@lj
2010-09-07 06:54 (ссылка)
Ужасно, неужели все настолько печально?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]m_a_m_o_n@lj
2010-09-07 07:03 (ссылка)
Ну да, где то в 4-ро медленне чем в варианте
с подзапросом в join-не.

В плане он всю таблицу blog (у меня film) шарашит, как я думал.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-07 13:42 (ссылка)
Это нормально, потому что тегами все протежено вдоль и поперек, одним тегом может быть помечено 30-50% таблицы, тут сканить по индексу просто смысла нет вообще.

(Ответить) (Уровень выше)


[info]alexclear@lj
2010-09-07 13:39 (ссылка)
Походу, это единственное, что сработало.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]m_a_m_o_n@lj
2010-09-08 04:16 (ссылка)
Очень интересно узнать, скольно в тестовой базе
постов, тегов и связей. И время по запросам здесь приведённым.

В sakila всего 1000 записей в films, все запросы
слишком быстро отрабатывают что бы разница была видна достоверно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-08 09:47 (ссылка)

mysql> select count(*) from wp_posts;
+----------+
| count(*) |
+----------+
| 72645 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from wp_term_relationships;
+----------+
| count(*) |
+----------+
| 186297 |
+----------+
1 row in set (0.04 sec)

mysql> select count(*) from wp_term_taxonomy;
+----------+
| count(*) |
+----------+
| 17442 |
+----------+
1 row in set (0.00 sec)

Зачем 17442 тегов/категорий, я не знаю, редакторы что-то намудили, в реальности при выборках используется штук может 50, одновременно в запросе - штук 10.

(Ответить) (Уровень выше)


[info]alexclear@lj
2010-09-08 09:49 (ссылка)
> И время по запросам здесь приведённым.

Для исходного, тривиального, около двух секунд.
Для варианта коллеги [info]metaclass@lj - 0.05 секунды для LIMIT 3000,100
Вариант коллеги [info]kvasimodo@lj пришлось прервать, не дождался конца, как и мой вариант с SELECT ... WHERE ID IN(SELECT ...)
Остальные варианты не смотрел.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]m_a_m_o_n@lj
2010-09-08 10:26 (ссылка)
>Для варианта коллеги [info]metaclass - 0.05 секунды для LIMIT 3000,100
mysql> select count(*) from wp_posts;
+----------+
| count(*) |
+----------+
| 72645 |
+----------+
1 row in set (0.06 sec)

Что то я не понимаю, как запрос с full-scan для таблицы posts может
отработать быстрее чем count(*)?

Покажите пожалуйста план.

P.S. У mysql есть фишка, он хорошо кеширует результаты запросов,
то что первый раз он мог считать за 10 секунд, если запрос выполнить
повторно не меняя базу - результат выпадет в миллисекунды.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-08 10:29 (ссылка)
> Что то я не понимаю, как запрос с full-scan для таблицы posts может
отработать быстрее чем count(*)?

Почему с full scan? Там выборка по индексу.
Вот он план.
С увеличением номера страницы будет расти и время.
Для LIMIT 28300, 100 будет около 0.5 секунды.

> P.S. У mysql есть фишка, он хорошо кеширует результаты запросов,
то что первый раз он мог считать за 10 секунд, если запрос выполнить
повторно не меняя базу - результат выпадет в миллисекунды.

Ненене, меня этим не провести, я жду минуты по три между запросами, само собой.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]m_a_m_o_n@lj
2010-09-08 10:45 (ссылка)
Хмм, наверное mysql достаточно умный что бы проверять записи в том
порядке в котором он их выдаёт и остановиться когда хватит.

Интересно, а сколько времени займёт поиск по редкому тегу, для которого
меньше 100 записей в базе?

P.S. >Ненене, меня этим не провести, я жду минуты по три между запросами, само собой.
Можно просто запрос немного исправить, "--" где нибудь добавить или пробелов,
тогда он будет выполнен как новый.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-08 13:02 (ссылка)
> Хмм, наверное mysql достаточно умный что бы проверять записи в том
порядке в котором он их выдаёт и остановиться когда хватит.

Конечно, он же группирует их по индексу.
Как только он наберет резалтсет, он остановится.

> Интересно, а сколько времени займёт поиск по редкому тегу, для которого
меньше 100 записей в базе?

Полный просмотр всего множества, ограниченного первыми двумя условиями.
Там где-то половина всей таблицы и выходит.
То есть, лучше, в данном случае, когда теги часто встречаются - быстрее сотня наберется.

(Ответить) (Уровень выше)


[info]alexclear@lj
2010-09-07 13:36 (ссылка)
ВАУ!
Да, это оно!
Спасибо, очень круто!

(Ответить) (Уровень выше)


[info]aefimov@lj
2010-09-07 16:58 (ссылка)
Это не mysql :)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-08 01:38 (ссылка)
Для мыскля немного другой запрос, но этот подход отлично сработал.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]aefimov@lj
2010-09-08 06:42 (ссылка)
Покажи, чем заменяется exists в mysql? И почему мой вариант с джойнами полная фигня, тоже можешь осветить, в двух словах?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alexclear@lj
2010-09-08 09:37 (ссылка)
EXISTS ничем не заменяется, он в мыскле и так есть, заменяется first 100, стандарно, limit 0,100
Вариант с джойнами плох тем, что в нем план, выбираемый мысклем, берет за первую таблицу не posts, а tags, что хорошо работало бы, если бы не группировка и сортировка. Из-за этого мыскль делает группировку и сортировку через временные буферы, а не используя индекс над posts.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]aefimov@lj
2010-09-08 09:51 (ссылка)
Ясно, спасибо. Про EXISTS не знал :)

(Ответить) (Уровень выше)


[info]alexclear@lj
2010-09-08 09:51 (ссылка)

(Ответить) (Уровень выше)

(Комментарий удалён)

[info]ext_55374@lj
2010-09-08 22:47 (ссылка)
Ботъ фофык.

(Ответить) (Уровень выше)


(Читать комментарии) -