Эффективный выбор отношения «многие ко многим» в H2 - PullRequest
0 голосов
/ 11 августа 2011

Я использую H2, и у меня есть база данных книг (таблицы Entries) и авторов (таблица Persons), связанных через отношение многие ко многим, которые сами хранятся в таблице Authorship.База данных довольно большая (900 000 человек + 2,5 млн. Книг).

Я пытаюсь эффективно выбрать список всех книг, созданных хотя бы одним автором, чье имя соответствует шаблону (LIKE '%шаблон%').Хитрость в том, что шаблон должен строго ограничивать количество подходящих авторов, и у каждого автора есть достаточно небольшое количество связанных книг.

Я пробовал два запроса:

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%')  AS p
  INNER JOIN Authorship AS au ON au.authorId = p.id
  INNER JOIN Entries AS e ON e.id = au.entryId;

и:

SELECT p.*, e.title FROM Persons AS p
  INNER JOIN Authorship AS au ON au.authorId = p.id
  INNER JOIN Entries AS e ON e.id = au.entryId
WHERE p.name like '%pattern%';

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

Когда я пытаюсь ОБЪЯСНИТЬ запросы, я вижу, что они действительно очень похожи (полное соединениетаблицы и только затем предложение WHERE), поэтому мой вопрос: как я могу добиться быстрого выбора, основанного на том факте, что фильтр по авторам должен привести к гораздо меньшему объединению с двумя другими таблицами?

Обратите внимание, что я пробовал те же запросы с MySQL и получил результаты в соответствии с тем, что я ожидал (выбор первого намного быстрее).

Спасибо.

Ответы [ 3 ]

1 голос
/ 17 августа 2011

Хорошо, вот что-то, что наконец-то сработало для меня.

Вместо выполнения запроса:

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p
  INNER JOIN Authorship AS au ON au.authorId = p.id
  INNER JOIN Entries AS e ON e.id = au.entryId;

... Я запустил:

SELECT title FROM Entries e WHERE id IN (
  SELECT entryId FROM Authorship WHERE authorId IN (
    SELECT id FROM Persons WHERE name LIKE '%pattern%'
  )
)        

Это не точно тот же запрос, потому что теперь я не получаю идентификатор автора в виде столбца в результате, но это делает то, что я хотел: использовать тот факт, что шаблон ограничивает количество авторовочень маленькое значение для поиска только по небольшому количеству записей.

Что интересно, это прекрасно работает с H2 (намного, намного быстрее, чем объединение), но с MySQL это ужасно медленно.(Это не имеет ничего общего с частью LIKE '% pattern%', см. Комментарии в других ответах.) Я полагаю, что запросы оптимизируются по-разному.

0 голосов
/ 11 августа 2011

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

Если вы хотите выполнить полнотекстовый поиск, mysqlне самая лучшая ставка у вас есть.Для решения подобных проблем обратитесь к другому программному обеспечению (например, solr ).

0 голосов
/ 11 августа 2011

SELECT * FROM Persons WHERE name LIKE '%pattern%' всегда будет LONG для таблицы строк с 900 000+ независимо от того, что вы делаете, потому что, когда ваш шаблон '%pattern%' начинается с %, MySql не может использовать индексы и должен выполнять полное сканирование таблицы.Вы должны изучить полнотекстовые индексы и функцию .

...