[英]Slow MySQL full text search
我正在使用此查詢在MySQL數據庫上執行全文搜索:
SELECT DISTINCT
questions.id,
questions.uniquecode,
questions.spam,
questions.questiondate,
questions.userid,
questions.description,
users.login AS username,
questions.questiontext,
questions.totalvotes,
MATCH(questions.questiontext, questions.uniquecode)
AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) AS relevance
FROM questions
LEFT JOIN users ON questions.userid = users.id
LEFT JOIN answer_mapping ON questions.id = answer_mapping.questionid
LEFT JOIN answers ON answer_mapping.answerid = answers.id
LEFT JOIN tagmapping ON questions.id = tagmapping.questionid
LEFT JOIN tags ON tagmapping.tagid = tags.id
WHERE questions.spam < 10
AND
(
MATCH(questions.questiontext, questions.uniquecode)
AGAINST ('rock guitarist chick*' IN BOOLEAN MODE)
OR MATCH(answers.answertext) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE)
OR MATCH (tags.tag) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE)
) GROUP BY questions.id ORDER BY relevance DESC
結果非常相關,但搜索速度非常慢,並且隨着表的增長而越來越慢。
表統計:
問題 - 400條記錄
索引
答案 - 3,635條記錄
索引
answer_mapping - 4,228條記錄
索引
標簽 - 1,847條記錄
索引
tagmapping - 3,389條記錄
索引
無論出於何種原因,當我刪除標記 映射和標記 JOINS時,搜索速度會大大提高。
您對如何加快查詢速度有任何提示嗎?
提前致謝!
好吧,你可以將你的連接組合成緩存視圖或額外的表或其他東西。 讓您的查詢緩存處於活動狀態,並將您的連接定義為選擇,以便可以緩存它。 確保足夠的內存等,但這不應該成為瓶頸。 很可能在你的情況下,因為...只有400條記錄? 沒什么......而且已經慢了? 因為其余的看起來不錯。 你在運行什么樣的硬件/配置?
但是,我認為這是錯誤的做法。 mysql不是為此而設計的。 實際上全文功能僅限於myisam。
你應該考慮使用dismax請求處理程序使用lucene / solr 。 它應該在大約50ms-100ms給你很好的結果,索引一些hundret千文件。 在某些時候你可以對它進行分片,因此記錄的數量是非常無限的。 加上你有更好的選擇,可以取得更好的結果。 例如,做模糊匹配或給予較新文檔更多權重或使標簽與標題更相關,進行后查詢分析,分面等...
您也可以嘗試運行OPTIMIZE TABLE questions
它幫助加快了我正在進行的項目中的類似查詢。
參見參考: https : //dev.mysql.com/doc/refman/5.7/en/fulltext-fine-tuning.html
由於多種原因,您對查詢的表述工作緩慢,但我不確定細節。 請提供EXPLAIN FORMAT=JSON SELECT ...
以供進一步討論。
同時,讓我們以一種應該更快的方式重寫查詢。 (它可能會擺脫你尚未遇到的錯誤。)
首先,讓我們構建一個調試。 它在3個獨立的查詢中的3個FT搜索,然后組合( UNION
) 只是 question_ids
從每個。
( SELECT question_id,
MATCH (... ) as relevance
FROM questions
WHERE MATCH (questiontext, ...) AGAINST ... )
UNION ALL
( SELECT am.question_id,
MATCH (... ) as relevance
FROM answers AS a
JOIN answer_mapping AS am ON am.answerid = a.id
WHERE MATCH (a.answertext) AGAINST ... )
UNION ALL
( SELECT tm.question_id,
MATCH (... ) as relevance
FROM tags AS t
JOIN tagsmapping tm ON ...
WHERE MATCH (t.tag) AGAINST ... )
注意每個子查詢是如何設計為以帶有FT索引的表開始 ,最后是question_id
。
現在,一個中間查詢:
SELECT question_id,
MAX(relevance) -- (this fixes the unseen bug)
FROM ( that query ) AS q1
GROUP BY question_id
ORDER BY relevance DESC -- optional; needed for `LIMIT`
LIMIT 20 -- to limit the rows, do it at this stage
如果運行得足夠快,並提供“正確”的question_ids
,那么我們可以繼續......
使用它作為子查詢來獲取其余數據:
SELECT .... -- the `questions` fields, using `q....`,
( SELECT login FROM users WHERE q.userid = id ) AS username
FROM ( the intermediate query ) AS q2
JOIN questions AS q
questions q.spam < 10
ORDER BY q2.relevance
是的,這是JOINing
回questions
,但原來要快。
請注意, GROUP BY
不在此處。 並且,如果內部查詢具有LIMIT
,則此處不需要它。
如果我沒有把一切都搞定,我道歉; 有比我預期更多的轉變。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.