2016-01-13 64 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同時具有優點和侷限性。