Базовая оптимизация с индексом для MySQL - PullRequest
2 голосов
/ 20 июля 2010

У меня есть вопрос об основной оптимизации базы данных MySQL. У меня есть 3 таблицы, статьи, теги и теги (которые являются таблицей соединений).

Articles         Taggings             Tags
id               id                   id
name             article_id           name
                 tag_id

Я получаю статьи, которые точно соответствуют указанным тегам, с помощью следующего запроса

SELECT *, COUNT(*) AS c
FROM articles AS a
JOIN taggings AS tng ON a.id = tng.article_id
JOIN tags AS t ON t.id = tng.tag_id
WHERE t.name IN ("Red","Green")
GROUP BY a.id
HAVING c = 2

Этот запрос медленный, поэтому я сделал EXPLAIN и получил следующие результаты:

альтернативный текст http://dl.dropbox.com/u/2306276/EXPLAIN%20results.png

Теперь я не совсем понимаю, что я здесь делаю, но я считаю, что "type: ALL" не годится, поэтому подумал, что я бы добавил индексы (BTREE) к article_id и tag_id в таблице taggings, и запустите запрос еще раз. альтернативный текст http://dl.dropbox.com/u/2306276/EXPLAIN%20results%202.png Что ж, это не выглядело лучше для моего необразованного глаза, с тем же количеством строк, что и у предыдущего, и тип по-прежнему ВСЕ в двух случаях.

Так может кто-нибудь сказать мне, где я иду не так, пожалуйста? индексы не помогут мне с этой проблемой?

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

Спасибо

[EDIT] - для комментариев Джея

Я добавил 10 тыс. Статей, 30 тыс. Тегов и 6 тегов, также добавил 2 индекса для tag.name и taggings.tag_id, выполнение запроса все еще занимало много времени, 0,5-1 секунда, ОБЪЯСНЕНИЕ ниже. альтернативный текст http://dl.dropbox.com/u/2306276/EXPLAIN%20results%203.png

Ответы [ 3 ]

2 голосов
/ 20 июля 2010

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

Обновление: попробуйте выполнить этот запрос

SELECT a.*
FROM articles AS a
JOIN taggings AS tng ON a.id = tng.article_id
JOIN tags AS t ON t.id = tng.tag_id
WHERE t.name IN ("Red","Green")
GROUP BY a.id
HAVING COUNT(DISTINCT t.id) = 2
1 голос
/ 20 июля 2010

Здесь происходит несколько вещей.

Во-первых, ваши таблицы в настоящее время очень маленькие. Когда таблица небольшая, СУБД часто обнаруживает, что быстрее читать все, а не использовать какой-либо индекс. Чтобы получить значимые результаты EXPLAIN, вам нужно получить реалистичное количество записей в таблицах.

Похоже, у вас есть поля "id", объявленные в качестве первичных ключей. Первичные ключи являются подклассом индексов, поэтому они должны быть доступны. Обратите внимание, что план объяснения указывает, что он использовал первичный ключ для поиска записи тега.

Очевидной отправной точкой этого запроса являются теги. Так что, если это важный запрос, я бы создал индекс Теги (имя). Тогда не нужно будет последовательно искать в таблице тегов.

Оттуда он должен искать теги по tag_id. Так что у вас должен быть индекс по этому вопросу.

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

Поэтому я думаю, что вы получите наиболее эффективный план с двумя индексами: теги (имя) и теги (tag_id).

1 голос
/ 20 июля 2010

Вы также можете попробовать использовать соединение с таблицами дважды вместо GROUP BY.Иногда это приводит к более быстрому запросу:

SELECT a.*
FROM articles AS a
JOIN taggings AS tng1 ON a.id = tng1.article_id
JOIN tags AS t1 ON t1.id = tng1.tag_id AND t1.name = "Red"
JOIN taggings AS tng2 ON a.id = tng2.article_id
JOIN tags AS t2 ON t2.id = tng2.tag_id AND t2.name = "Green"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...