2012-03-06 50 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

相关问题