Я унаследовал большую, некрасивую базу данных MySQL 5.7 и собираюсь оптимизировать некоторые запросы.
В частности, пользователь хочет найти 7 разных var_char
столбцов ... в 7 разных таблицах.
Очевидно, я могу объединить 7 таблиц и отфильтровать для LIKE '%search term%'
, но я бы хотел использовать MATCH...AGAINST
a FULLTEXT
index.
Я создал индексы:
ALTER TABLE table1 ADD FULLTEXT INDEX (origname);
ALTER TABLE table2 ADD FULLTEXT INDEX (byline);
ALTER TABLE table3 ADD FULLTEXT INDEX (copyright);
ALTER TABLE table4 ADD FULLTEXT INDEX (source);
ALTER TABLE table5 ADD FULLTEXT INDEX (image_title);
ALTER TABLE table6 ADD FULLTEXT INDEX (photo_info);
ALTER TABLE table7 ADD FULLTEXT INDEX (alt_text);
Я попробовал следующее, но производительность была ужасной ... есть ли хороший способ выполнить полнотекстовый поиск по нескольким таблицам?
SELECT
MATCH(table1.name) AGAINST ('search term') as name,
MATCH(table2.byline) AGAINST ('search term') as byline,
MATCH(table3.copyright) AGAINST ('search term') as copyright,
MATCH(table4.source) AGAINST ('search term') as copyright,
MATCH(table5.image_title) AGAINST ('search term') as image_title,
MATCH(table6.photo_info) AGAINST ('search term') as photo_info,
MATCH(table7.alt_text) AGAINST ('search term') as alt_text
FROM table1
LEFT JOIN table2 on table2.entity_id = table1.fid
LEFT JOIN table3 on table3.entity_id = table1.fid
LEFT JOIN table4 on table4.entity_id = table1.fid
LEFT JOIN table5 on table5.entity_id = table1.fid
LEFT JOIN table6 on table6.entity_id = table1.fid
LEFT JOIN table7 ON table7.alt_text = table1.fid
WHERE
MATCH(table1.name) AGAINST ('search term') OR
MATCH(table2.byline) AGAINST ('search term') OR
MATCH(table3.copyright) AGAINST ('search term') OR
MATCH(table4.source) AGAINST ('search term') OR
MATCH(table5.image_title) AGAINST ('search term') OR
MATCH(table6.photo_info) AGAINST ('search term') OR
MATCH(table7.alt_text) AGAINST ('search term');
В идеале я бы просто использовал Elasticsearch / Lucene/ Solr и т. Д., Но давайте на минутку предположим, что я не могу использовать ни одну из тех вещей, что я ограничен MySQL.Есть ли хороший способ сделать это?
Вот вывод EXPLAIN EXTENDED
:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table1 NULL ALL NULL NULL NULL NULL 557535 100 NULL
1 SIMPLE table2 NULL ref entity_id entity_id 4 mydb.table1.fid 1 100 NULL
1 SIMPLE table3 NULL ref entity_id entity_id 4 mydb.table1.fid 1 100 NULL
1 SIMPLE table4 NULL ref entity_id entity_id 4 mydb.table1.fid 1 100 NULL
1 SIMPLE table5 NULL ref entity_id entity_id 4 mydb.table1.fid 1 100 NULL
1 SIMPLE table6 NULL ref entity_id entity_id 4 mydb.table1.fid 1 100 NULL
1 SIMPLE table7 NULL ALL field_file_image_alt_text_value NULL NULL NULL 203374 100 Using where
==========================================
Ответ : приведенное ниже решение Bomar является правильным подходом, но MySQL 5.7 не помогне нравится его синтаксис.Мне пришлось кодировать это следующим образом:
ВЫБРАТЬ fid, scoredName AS, origname AS "Имя файла", NULL AS Byline, NULL AS Copyright, NULL AS Source, NULL AS "Заголовок изображения", NULL AS "Информация о фотографии ", NULL AS" Alt text "
SELECT fid, MATCH(origname) AGAINST ('search term') AS scoredName, origname, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
FROM table1
WHERE MATCH(origname) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(byline) AGAINST ('search term') AS scoredByline, NULL AS N3, byline, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
FROM table2
WHERE MATCH (byline) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(copyright) AGAINST ('search term') AS scoredCopyright, NULL AS N3, NULL AS N4, copyright, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
FROM table3
WHERE MATCH (copyright) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(source) AGAINST ('search term') AS scoredSource, NULL AS N3, NULL AS N4, NULL AS N5, source, NULL AS N7, NULL AS N8, NULL AS N9
FROM table4
WHERE MATCH (source) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(image_title) AGAINST ('search term') AS scoredTitle, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, image_title, NULL AS N8, NULL AS N9
FROM table5
WHERE MATCH(image_title) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(full_photo_info) AGAINST ('search term') AS scoredPhotoInfo, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, full_photo_info, NULL AS N9
FROM table6
WHERE MATCH(full_photo_info) AGAINST ('search term')
UNION
SELECT entity_id, MATCH(file_image_alt_text) AGAINST ('search term') as scoredaltText, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, file_image_alt_text
FROM table7
WHERE MATCH(file_image_alt_text) AGAINST ('search term')
) AS g
GROUP BY fid, score, origname, byline, copyright, source, "Image title", "Photo info", "Alt text"
ORDER BY score DESC;
Для объяснения: UNION
просто объединяет последующие запросы в столбцы, заданные первым запросом.
Следовательно, все онидолжно иметь одинаковое количество столбцов, и поэтому вы видите все эти значения NULL
.
Но у вас не может быть двух столбцов с одинаковыми именами, поэтому вы должны иметь псевдоним каждый NULL
.
Далее я, вероятно, взвешиваю различные индексы, умножая более важные на постоянные.