T-SQL - 如何更快地使用多个LIKE子句进行SELECT查询?

时间:2013-08-15 16:39:04

标签: sql sql-server tsql

我有一个搜索功能,看起来像这样的新闻文章(包含超过5个搜索项目):

SELECT TOP 5 *
FROM NewsArticles
WHERE (headline LIKE '% sustainable %'OR
headline LIKE '% sustainability %' OR
headline LIKE '% conservation %' OR
headline LIKE '% environmental % OR
headline LIKE '% environmentally %') 
OR
(body LIKE '% sustainable %'OR
body LIKE '% sustainability %' OR
body LIKE '% conservation %' OR
body LIKE '% environmental % OR
body LIKE '% environmentally %')
ORDER BY publishDate DESC 

此查询旨在提取与可持续发展相关的前5个新闻报道,并位于我的主要可持续发展主页上。但是,运行需要一段时间,页面加载速度很慢。所以我正在寻找加快速度的方法。有这么多LIKE条款似乎很麻烦,所以我尝试了像这样的JOIN:

CREATE TABLE #SearchItem (Search varchar(255))

INSERT INTO #SearchItem VALUES
('sustainable'),
('sustainability'),
('conservation'),
('environmental'),
('environmentally')

SELECT TOP 5 *
FROM NewsArticles as n
JOIN #SearchItem as s
ON n.headline COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %' OR 
n.body COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %'
ORDER BY n.publishDate DESC

这似乎对性能非常有效,但似乎有时会带回一些重复的文章,其中一个搜索词出现在正文和标题中(通常就是这种情况)。我尝试使用'SELECT DISTINCT TOP 5 *'这个词,但是这给了我一个错误,'ntext数据类型不能被选为DISTINCT,因为它不具有可比性'。是不是在没有进行2次单独搜索和使用UNION的情况下停止重复这个重复?

5 个答案:

答案 0 :(得分:4)

如果您正在进行这些类型的搜索,则应使用全文搜索。您需要在BOL中阅读有关如何设置它的内容,因为它很复杂。但是,当您将通配符作为第一个字符时,SQL Server无法使用索引,这就是为什么这很慢。

答案 1 :(得分:2)

如果有新闻文章密钥,您可以使用查询连接回自身,例如:

select top 5 *
from NewsArticles as na
join 
    ( 
        SELECT distinct idNo , publishDate 
        FROM NewsArticles as n
        JOIN #SearchItem as s
        ON n.headline COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %' OR 
        n.body COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %'
    ) as sk
        on sk.idNo = na.idNo
ORDER BY sk.publishDate DESC

答案 2 :(得分:1)

由于您在多个单词上获得多次点击,您可以使用所选的ID作为实际选择文章的过滤器:

Select TOP 5 * 
from NewsArticles 
where ID in (SELECT ID
    FROM NewsArticles as n
    JOIN #SearchItem as s
    ON n.headline COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %' OR 
       n.body COLLATE DATABASE_DEFAULT LIKE '% ' + s.Search + ' %'
)
ORDER BY publishDate DESC

它应该仍然相当快(与原始查询相比)并且无重复。

(正如在Rawheiser的回答中,假设ID字段实际存在:))

答案 3 :(得分:1)

您也可以尝试全文搜索。像

这样的东西
SELECT TOP 5 * FROM NewsArticles 
WHERE CONTAINS((headline,body), 'FORMSOF(INFLECTIONAL, sustainable) OR conservation OR FORMSOF(INFLECTIONAL, environmental)')

但是,正如HLGEM所说,阅读有关设置FTS的信息非常重要。只需为这两列创建索引就足够了,因为您正在搜索单个单词,但是一旦添加了短语,就要开始编辑停用词和断路器以及干扰词。

答案 4 :(得分:0)

我会这样的事情

enter image description here

我会编写一个不区分大小写的索引过程,该过程将在晚上运行,即:

  • 解析文章,在SEARCH_TERM中插入找到的任何新单词
  • SEARCH_INDEX中插入一个元组,该元组表示给定文章具有给定的搜索字词
  • NEWS_ARTICLE标记为已编入索引。
  • 下一次运行将仅索引未被识别的文章

示例查询可以是这样的,并且由于您不会使用LIKE而快速点亮:

select
    distinct n.headline
from
    search_item s
    join search_index x on (s.id = x.search_item_id)
    join news_article n on (x.news_article_id = n.id)
where
    s.term in ('sustainable','sustainability','conservation',
               'environmental','environmentally')

稍后您可以为搜索字词创建同义词,并创建一个返回带有同义词的字词的视图,如果您希望将来进行更多的语义搜索。