我继承了一个庞大的丑陋MySQL 5.7数据库,并希望优化一些查询。
具体来说,用户希望在7个不同的表中搜索7个不同的var_char
列。
很明显,我可以联接7个表并为LIKE '%search term%'
进行过滤,但是我很想使用MATCH...AGAINST
和FULLTEXT
索引。
我创建了索引:
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不喜欢他的语法。我不得不这样编码:
SELECT fid,scoreedName AS分数,origname AS“文件名”,NULL AS副行,NULLAS版权,NULL AS源,NULLAS“图像标题”,NULLAS“照片信息”,NULLAS“替代文字” < / p>
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
加上别名。
接下来,我可能会通过将更重要的索引乘以一个常数来加权不同的索引。
答案 0 :(得分:0)
OR
使MySQL难以优化。使用与UNION
组合的单独查询。
这假设每个相关表中的每个entity_id
仅一行。如果不是,则原始查询将返回所有匹配行的叉积,而这只会返回每个表的最大匹配数。
SELECT fid, MAX(name) AS name, MAX(byline) AS byline, MAX(copyright) AS copyright, MAX(source) AS source, MAX(image_title) AS image_title, MAX(photo_info) AS photo_info, MAX(alt_text) AS alt_text
FROM (
SELECT fid, MATCH(name) AGAINST ('search term') as name, NULL AS byline, NULL AS copyright, NULL AS source, NULL AS image_title, NULL AS photo_info, NULL AS alt_text
FROM table1
WHERE MATCH(name) AGAINST ('search term')
UNION
SELECT entity_id, NULL, MATCH(byline) AGAINST ('search term'), NULL, NULL, NULL, NULL, NULL
FROM table2
WHERE MATCH(byline) AGAINST ('search term')
UNION
SELECT entity_id, NULL, NULL, MATCH(copyright) AGAINST ('search term'), NULL, NULL, NULL, NULL
FROM table3
WHERE MATCH(copyright) AGAINST ('search term')
UNION
SELECT entity_id, NULL, NULL, NULL, MATCH(source) AGAINST ('search term'), NULL, NULL, NULL
FROM table4
WHERE MATCH(source) AGAINST ('search term')
UNION
SELECT entity_id, NULL, NULL, NULL, NULL, MATCH(image_title) AGAINST ('search term'), NULL, NULL
FROM table5
WHERE MATCH(image_title) AGAINST ('search term')
UNION
SELECT entity_id, NULL, NULL, NULL, NULL, NULL, MATCH(photo_info) AGAINST ('search term'), NULL
FROM table6
WHERE MATCH(photo_info) AGAINST ('search term')
UNION
SELECT entity_id, NULL, NULL, NULL, NULL, NULL, NULL, MATCH(alt_text) AGAINST ('search term')
FROM table7
WHERE MATCH(alt_text) AGAINST ('search term')
) AS u
GROUP BY fid
答案 1 :(得分:0)
建立一个单一表,其目的是进行此类搜索。它将只有一个文本列,该列会收集其他各个表中的所有单词,并具有message() {
if(!this.toastOpen) {
this.message.alert('Hi Welcome');
}
}
的ID。
结果查询:
JOINing
当然,要求您在填充任何其他表时都填充SELECT ...
FROM search_table AS st
WHERE MATCH (st.txt) AGAINST (... IN BOOLEAN MODE)
JOIN table1 USING(id)
JOIN table2 USING(id) -- or whatever is needed for the JOIN ON
JOIN table3 USING(id)
...;
。但是,如果您删除某些ID,它不会“要求”您进行清理。 search_table
根本不会在其他表中找到行。
JOIN
将设置为类似
txt