2016-05-04 2 views
0

У меня есть несколько скриптов CURL, которые собирают данные со многих внутренних сайтов компании в общую базу данных. Каждый скрипт называется «экземпляром». Данные добавляются в базу данных в виде записей. Каждая запись имеет несколько «полей», которые представляют собой пару ключ-> значение. Поскольку клавиши для каждой записи являются динамическими и могут быть любыми (даже в одном экземпляре), они не жестко закодированы в таблице MySQL.MySQL запросы с MATCH и AGAINST подвешивание

Так есть эти таблицы:

  1. записи - содержат список записей, каждая из которых связана с экземпляром
  2. record_fields - содержит список полей, связанных с записью
  3. record_fields_labels - в основном список этикеток. Это сохраняется в базе данных для экономии места (т. Е. Вместо полей record_fields есть тысячи полей, которые имеют метку «Дата статьи», все они будут иметь номер 8, который является идентификатором записи в record_labels, которая имеет «Дата статьи» «как его ценность».

record_fields и record_fields_labels оба MyISAM таблицы с индексом FULLTEXT на «содержание» (столбец в record_fields, который содержит фактические данные) и «ярлык» (столбец в record_fields_labels, который имеет имя метки).

База данных содержит миллионы записей - для каждого умножить количество полей записи ... Когда экземпляры бежать, чтобы проверить, существует ли уже запись в базе данных, они делают следующий SQL-запрос:

SELECT r.id FROM records r INNER JOIN record_fields rf ON rf.record_id=r.id INNER JOIN record_fields_labels as rfl ON rf.label=rfl.id WHERE r.instance IN (120) AND MATCH (rf.content) AGAINST ('"http://xxxx.xxxx/xxx.xxx.xxx"' IN BOOLEAN MODE) AND MATCH (rfl.label) AGAINST ('"Article URL"' IN BOOLEAN MODE) GROUP BY r.id 

В этом примере http://xxxx.xxxx/xxx.xxx.xxx - это URL-адрес статьи, скрипт проверяет, существует ли она в системе.

TL; DR

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

Все, что я хочу, это показать, существует ли такая запись или нет. Это не проблема индексирования, а что-то особенное, что нужно делать с MATCH AGAINST. Я предпочитаю избегать добавления дополнительного индекса всего содержимого (в дополнение к индексу FULL TEXT) для экономии места.

Кто-нибудь знает, что вызывает эту проблему?

Благодаря

+0

Вы запустили 'EXPLAIN' на своем SQL, чтобы увидеть, как запрос запускается движком? – syck

+0

И: как правило, разумно сконструированный индекс является наиболее эффективным способом найти что-либо или доказать его существование. Это для чего. – syck

ответ

0

Похоже, вы используете полнотекстовый индекс, где вы не должны, в частности, для наклеек. Если они просты и четко определены, нормальный индекс будет в порядке. Если вам нужно различать «Дата статьи» и «Дата блога», например, используйте одно поле для типа контента и одно для типа данных.

При поиске фразы с использованием MATCH AGAINST ... В BOOLEAN MODE вы фактически ищете одни и те же слова в том же порядке, а не в полной строке.см DOCS

Поиск «http://xxxx.yyy/www.zzz.mmm» в содержании поля фактически совпадают «некоторое содержание здесь HTTP, хххх. ууу WWW! ZZZ ммм? да, пожалуйста, больше содержание» и это при условии, ваш полный текст минимальной длины слова составляет 3 или Меньше. Для производительности и логики это неверный индекс.

Я бы серьезно подумал об изменении структуры данных, чтобы вы не помещали индексы FULL TEXT на URL-адреса и метки. Это, вероятно, сэкономит вам больше места, чем избегать использования обычных индексов.

Смежные вопросы