Лучший способ хранить «метки» для скорости в огромном столе - PullRequest
2 голосов
/ 02 сентября 2011

Я разрабатываю большой контент-сайт с таблицей «content», содержащей более 50 миллионов записей.Вот структура таблицы:

contain id(INT11 INDEX), 
name(varchar150 FULLTEXT), 
description (text FULLTEXT), 
date(INT11 INDEX)

Я хочу добавить «теги» к этому содержимому.

Я думаю, что 2 метода:

  1. Создайте столбец тегов varchar (255 FULLTEXT) в содержимом таблицы.Сохраните все теги, разделенные запятыми, и ищите построчно (что, я думаю, будет медленно), используя MATCH & AGAINS.

  2. Составьте 2 таблицы.Первое имя таблицы «tag» с столбцами id, tag (varchar (30 INDEX или FULLTEXT?)), «Contents_tags» с id, tag_id (int11 INDEX) и content_id (int11 INDEX) и поиск содержимого с помощью JOINS из 3 таблиц (content- contents_tags - теги), чтобы получить все содержимое с тегом (ами).

Я думаю, что это медленно и убивает память, потому что ОГРОМНОЕ СОЕДИНЕНИЕ из 50M таблиц * contents_tags * tags.

Какой метод лучшехранить теги, чтобы сделать его максимально эффективным?Какой самый быстрый способ поиска по тексту (например, «фильм 3d 2011» и простой тег «видео») и для поиска содержимого .?

Размер таблицы (около 5 ГБ без тегов),Таблица является MYISAM, потому что мне нужно хранить имя и описание содержимого таблицы в FULLTEXT для поиска по строке (пользователи теперь могут искать по этим полям), и мне нужна наилучшая скорость для поиска по тегам.

Любой сопыт в этом?

Спасибо!

1 Ответ

7 голосов
/ 02 сентября 2011

FULLTEXT-индексы на самом деле не так быстры, как вы думаете.

Используйте отдельную таблицу для хранения ваших тегов:

Table tags
----------
id integer PK
tag varchar(20)

Table tag_link
--------------
tag_id integer foreign key references tag(id)
content_id integer foreign key references content(id)
/* this table has a PK consisting of tag_id + content_id */

Table content
--------------
id integer PK
......

ВЫ ВЫБИРАЕТЕ все содержимое с тегом x, используя:

SELECT c.* FROM tags t
INNER JOIN tag_link tl ON (t.id = tl.tag_id)
INNER JOIN content c ON (c.id = tl.content_id)
WHERE tag = 'test'
ORDER BY tl.content_id DESC /*latest content first*/
LIMIT 10;

Из-за внешнего ключа все поля в tag_links индексируются индивидуально.
Тест WHERE tags = 'выбирает 1 (!) Запись.
Уравнивает это с10 000 тегов.
И Equi-joins , которые с 1 записью контента каждая (каждая tag_link указывает только на 1 контент).
Из-за ограничения 10 MySQL перестанет искать, как толькоимеет 10 элементов, так что в действительности он просматривает только 10 записей tag_links.
content.id является автоинкрементным, поэтому большие числа являются очень быстрым прокси для новых статей.

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

В этом нет «если-то-или-но», это самый быстрый способ.

Обратите внимание, что, поскольку существует не более нескольких 1000 тегов, любой поиск будет намного быстрее, чем копирование в таблице полного содержимого.

Наконец,
CSV-поляочень плохая идея, никогда не используйте ее в базе данных.

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