2012-03-06 34 views
7

我有一個數據庫,每天有超過500,000個條目,有75,000多行。在SQL中搜索最有效的方法?

每一行都有一個標題和描述。

我創建了一個RSS源,它爲您提供特定搜索術語的最新條目(例如,http://site.com/rss.rss?q=Pizza會爲搜索項「Pizza」輸出RSS)。

我想知道爲此編寫SQL查詢的最佳方法是什麼。現在我有:

SELECT * 
FROM 'table' 
WHERE (('title' LIKE %searcherm%) OR ('description' LIKE %searcherm%)) 
LIMIT 20; 

但問題是它需要2到10秒執行查詢。

有沒有更好的方式來編寫查詢,我必須緩存結果(我會怎麼做呢?),或將改變數據庫結構加快查詢(索引?)

+0

可能更快單個線程之前使用CONCAT /叉加工成2個簡單querys: 從'選擇表格,其中標題限制20' 然後 '從表中選擇描述限制20' 有點事情,然後做與您的服務器端的連接/列表concat技術 – 2012-03-06 18:42:13

+0

solr,lucene,sphinx? – 2012-03-06 18:44:28

回答

8

一個相對簡單的此解決方案將包含在這兩個一個FULLTEXT指數字段,然後使用此索引進行搜索。

ALTER TABLE table ADD FULLTEXT(title, description); 

那麼你就需要進行搜索,你會做到以下幾點:

SELECT id FROM table 
WHERE MATCH (title, description) AGAINST ('keyterm'); 

全文索引的搜索是包含在大多數SQL數據庫自動解決方案。與做喜歡相比,速度更快。這也針對您的特定情況進行了優化,因爲您只對自然語言搜索條件感興趣。

同樣,全文索引具有一些用於檢測相關性的限制算法。你可以閱讀更多關於它here

編輯

在ALTER語句,我錯過了全文索引的名字,它應該是:

ALTER TABLE table ADD FULLTEXT ft_index_name(title, description); 
+0

我會嘗試。謝謝! – supercoolville 2012-03-06 18:50:13

+0

請注意,這隻適用於MyISAM表格,而不適用於InnoDB。 – 2012-03-06 19:00:39

+1

非常感謝!我測試了這一點,它使我的搜索速度平均提高了14倍!!!!!!! – supercoolville 2012-03-07 07:22:52

-2

東西幾個指針:在您的select語句中刪除*並僅提取搜索條件,並確保將索引添加到正在搜索的列中。

SELECT `title`,`description` 
FROM `table` 
WHERE `title` LIKE '%$searchterm%' OR `description` LIKE '%$searchterm%' LIMIT 25; 
+0

「在選擇語句中刪除*並只提取搜索條件」 - 那麼您如何知道他想要檢索的內容? – 2012-03-06 18:43:33

+0

我不知道,但是根據他的WHERE子句,我可以確定他需要至少標題和描述。無論如何,最好指定你的表格而不是通配符,他問的是如何加快查詢速度並消除通配符是第一步。 – 2012-03-06 18:45:39

+0

有一個限制20 ..我懷疑它會產生任何可衡量的差異 – 2012-03-06 18:47:07

-2
  1. 你創建titledescription的指數?
  2. 對於全文搜索功能,您應該考慮Sphinx

感謝您的評論泰勒。

我重申我的回答:

1)創建於titledescription列的索引,但您的查詢將被限制在下面的例子中,這是不理想的找到所有相關行:

SELECT * 
FROM 'table' 
WHERE title LIKE 'searcherm%' OR description LIKE 'searcherm%' 
LIMIT 20; 

2)正如其他人所提到的,使用MySQL Full-Text Search,但您僅限於MyISAM表引擎,因爲它不適用於InnoDB。但是,您可以在MySQL中混合引擎,因此即使所有其他表都是InnoDB,也可以創建此表MyISAM。

3)使用外部全文搜索引擎,如Sphinx。這將爲您提供更多相關的搜索結果(MySQL全文搜索還有很多不足之處),它會更好地發揮作用,它將全文搜索的負擔從數據庫中抽離出來。

+2

索引在這裏沒有幫助。像'%foo%'從不使用索引。這是他的真正問題。 – 2012-03-06 18:43:13

4

嘗試:

SELECT * FROM table 
WHERE MATCH (title,description) AGAINST (searchterm); 

請務必加上標題全文索引,描述一起。

不要試圖重新發明輪子。 MATCHAGAINST都是provided by mysql這樣做,讓您的生活變得輕鬆。但是,請注意MyISAM表格上的全文搜索。您也可以在InnoDb上使用can workaround。你可以簡單地通過改變如表添加FT指數:

ALTER TABLE table ADD FULLTEXT(title,description); 
+0

這是唯一可行的答案。提及您需要爲這些列添加全文索引,並且您必須使用MyISAM表。 – 2012-03-06 18:49:19

+0

@FrancisAvila更新了我的答案。 – jerrymouse 2012-03-06 18:59:40

2

如果您使用的是與LIKE '%term%'查詢索引無法使用。只有當您使用像'term%'這樣的查詢時,才能使用它們。想想帶有標籤的地址簿,你可以找到真正快速的聯繫人,以字母L開頭,但要在單詞的某處找到與on的聯繫人,則必須掃描整個地址簿。

更好的替代辦法是使用全文索引:

CREATE FULLTEXT INDEX title_desc 
ON table (title, description) 

然後在查詢:

SELECT title, description FROM table 
WHERE MATCH (title, description) AGAINST ('+Pizza') 
0

我會去與JohnB的或gtr32x的答案(全文索引)。爲了補充他們的回答,有創建一個簡單的全文索引,這是簡單的手工方式,它是超級快...

拆分標題和描述成關鍵字,並將其放置在一個Keywords表,其中有一個外鍵原來的RSS文章。確保Keywords中的關鍵字列已編入索引。你可以這樣做:

SELECT DISTINCT ra.* 
FROM RssArticle ra 
INNER JOIN Keywords k ON k.ArticleID = ra.ArticleID 
    WHERE k IN ('SearchTerm1', 'SearchTerm2', 'SearchTerm3') 
LIMIT 20; 

而且速度很快!

+0

林不知道你的意思是... – supercoolville 2012-03-06 18:57:04

0

請嘗試以下四個查詢的:

select * from myTable where concat_ws(' ',title,description) like '%pizza%'; 
select * from myTable where concat_ws(' ',title,description) regexp '.*pizza+.*'; 
select title,description from myTable where concat_ws(' ',title,description) like '%pizza%'; 
select title,description from myTable where concat_ws(' ',title,description) regexp '.*pizza+.*'; 

點是搜索

+0

這是約2倍,但沒有匹配反應速度快 – supercoolville 2012-03-07 07:28:37

相關問題