2016-01-13 92 views
0

我写了一个搜索查询来搜索相似的名字。它适用于电源组的标签,它按相似性排序。例如,如果搜索文本是:shakespeare tragedy hamlet如何优化搜索SQL查询?

生成的SQL是:

SELECT DISTINCT id FROM (
    (SELECT * FROM books 
     WHERE name LIKE '%shakespeare%' 
     AND name LIKE '%tragedy%' 
     AND name LIKE '%hamlet%' limit 10) 
    UNION 
    (SELECT * FROM books 
     WHERE name LIKE '%shakespeare%' 
     AND name LIKE '%tragedy%' limit 10) 
    UNION 
    (SELECT * FROM books 
     WHERE name LIKE '%shakespeare%' 
     AND name LIKE '%hamlet%' limit 10) 
    UNION 
    (SELECT * FROM books 
     WHERE name LIKE '%tragedy%' 
     AND name LIKE '%hamlet%' limit 10) 
    UNION 
    (SELECT * FROM books WHERE name LIKE '%shakespeare%' limit 10) 
    UNION 
    (SELECT * FROM books WHERE name LIKE '%tragedy%' limit 10) 
    UNION 
    (SELECT * FROM books WHERE name LIKE '%hamlet%' limit 10) 
) limit 10 

有两个问题:

  1. 的发电机组在我的查询创建2^tags - 1工会,这意味着如果有些人想要精确并使用6个标签,这将是63个工会,它使我的查询变得更慢。

  2. 如果第一个联合返回10行,其他联合是无用的。

有没有一种方法来优化此查询?

+0

生成此sql的代码在哪里?你只是在寻找一个将包含所有标签的行吗?或者其中的1个足够像查询的最后3行 – sagi

+0

@sagi我相信每个人都知道powerset是如何工作的,这就是为什么我没有经历代码。我正在寻找按相似性排序的类似行。 –

回答

0

我们可以获得名称与过去标记相似的所有boosk并添加基于相似性的自定义ORDER BY。如果名称中包含标签+1,如果不为0,所以,如果名称中包含的所有3个标签和为3,如果只是一个总和为1

SELECT DISTINCT id 
FROM books 
where name LIKE '%shakespeare%' 
    OR name LIKE '%tragedy%' 
    OR name LIKE '%hamlet%' 
ORDER BY IF(INSTR(name, 'shakespeare')>0,1,0)+ 
     IF(INSTR(name, 'tragedy')>0,1,0)+ 
     IF(INSTR(name, 'hamlet')>0,1,0) DESC 
LIMIT 10 

UPDATE:ORDER BY可以基于总和或只是逗号

+0

按顺序降序排列。 –

+0

是的,降序。抱歉忘记提及 – StanislavL

+0

请修改您的代码 –

0

如果切换到FULLTEXT指数和使用

MATCH(name) AGAINST('shakespeare tragedy hamlet') 

你可以得到一个有点道理排序,并运行很多更快。

如果你想坚持shakespeare在字符串中,但其他人是可选的,这会更好:'+shakespeare tragedy hamlet'

注意:FULLTEXT同时具有优点和局限性。