2009-03-20 3 views
4

Как более общий случай this question, потому что я думаю, что это может представлять интерес для большего числа людей ... Каков наилучший способ выполнить полнотекстовый поиск на двух таблицах? Предположим, что есть три таблицы, одна для программ (с submitter_id) и одна для тегов и описаний с помощью object_id: внешние ключи, относящиеся к записям в программах. Мы хотим, чтобы submitter_id программ с определенным текстом в их тегах или описаниях. Мы должны использовать MATCH AGAINST по причинам, по которым я не буду здесь заниматься. Не зацикливайтесь на этом аспекте.MySQL FULLTEXT Search Across> 1 Таблица

programs 
    id 
    submitter_id 
tags_programs 
    object_id 
    text 
descriptions_programs 
    object_id 
    text 

следующие работы и выполняет в 20мс или так:

SELECT p.submitter_id 
FROM programs p 
WHERE p.id IN 
    (SELECT t.object_id 
    FROM titles_programs t 
    WHERE MATCH (t.text) AGAINST ('china') 
UNION ALL 
    SELECT d.object_id 
    FROM descriptions_programs d 
    WHERE MATCH (d.text) AGAINST ('china')) 

, но я попытался переписать это как ПРИСОЕДИНЯЙСЯ следующим образом, и она работает в течение очень долгого времени. Я должен убить его через 60 секунд.

SELECT p.id 
FROM descriptions_programs d, tags_programs t, programs p 
WHERE (d.object_id=p.id AND MATCH (d.text) AGAINST ('china')) 
OR (t.object_id=p.id AND MATCH (t.text) AGAINST ('china')) 

Просто из любопытства я заменил OR символом AND. Это также работает за несколько миллисекунд, но это не то, что мне нужно. Что случилось с вышеупомянутым вторым запросом? Я могу жить с UNION и subselects, но я хотел бы понять.

ответ

5

Присоединиться к фильтрам (например, присоединиться к результатам), не пытаться присоединиться, а затем фильтровать.

Причина в том, что вы теряете использование своего полнотекстового индекса.

Уточнение в ответ на комментарий: Я использую слово join generically здесь, а не как JOIN, а как синоним объединения или объединения.

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

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

+0

Является ли синтаксис для этого отличным от первого примера? –

+0

Я не следую, Маркус. (a) Как бы вы написали «присоединиться к фильтрам»? и (б) «вы теряете использование вашего полнотекстового индекса. ??? –

0

Если вы присоединитесь к обеим столам, вы получите множество записей для проверки. Как пример, если обе таблицы имеют 100 000 записей, их полное присоединение дает вам 10 000 000 000 записей (10 миллиардов!).

Если вы изменили OR на AND, вы позволите движку отфильтровывать все записи из таблицы description_programs, которая не соответствует «china», и только , затем, соединяющей с titles_programs.

В любом случае, это не то, что вам нужно, поэтому я рекомендую придерживаться пути UNION.

+0

Правильно ли это математика? Если у меня есть 100 000 программ, и у каждого из них есть заголовок, почему бы не присоединить программы и теги всего 100 000 строк? И если вы также присоединяетесь к 100 000 описаний, разве у вас все еще есть только 100 000 строк? –

+0

Если вы хотите сопоставлять программы с титрами, то затем в предложение join. Если вы просто присоединитесь к ним без предложения ON, все строки будут сопоставлены. Сделайте что-то вроде FROM description_programs d JOIN tags_programs t ON d.object_id = t.objecT_id JOIN программы p ON t.object_id = p.id – Seb

0

Союз - это правильный путь. Присоединение будет сразу затягиваться как с полными текстовыми индексами, так и через несколько проверок.

1

На всякий случай вы не знаете: MySQL имеет встроенный оператор, называемый EXPLAIN, который можно использовать для просмотра того, что происходит под поверхностью. Об этом много статей, поэтому я не буду вдаваться в подробности, но для каждой таблицы он дает оценку количества строк, которые ему нужно будет обрабатывать. Если вы посмотрите на столбец «rows» в результате EXPLAIN для второго запроса, вы, вероятно, увидите, что количество строк довольно велико и, конечно, намного больше, чем от первого.

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

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