MySQL跨多个索引搜索

时间:2018-10-01 21:26:35

标签: mysql search indexing

我继承了一个庞大的丑陋MySQL 5.7数据库,并希望优化一些查询。

具体来说,用户希望在7个不同的表中搜索7个不同的var_char列。

很明显,我可以联接7个表并为LIKE '%search term%'进行过滤,但是我很想使用MATCH...AGAINSTFULLTEXT索引。

我创建了索引:

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加上别名。

接下来,我可能会通过将更重要的索引乘以一个常数来加权不同的索引。

2 个答案:

答案 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