2

我正在查询一个表,其中包含用户搜索的顶级结果的全文索引,然后将通配符搜索的结果附加到该表的末尾。

这是我稍微简化的 SQL ......

SELECT TOP(@top) * FROM     
(       
    SELECT TOP (@top) ft.[RANK], p.ProductID, p.Name FROM dbo.Product p 
    INNER JOIN FREETEXTTABLE(dbo.Product, *, @search_term) AS ft ON p.ProductID = ft.[KEY]
    ORDER BY ft.[RANK] * p.Popularity DESC

    UNION ALL

    SELECT TOP (@top) 0 AS [RANK], p.ProductID, p.Name FROM dbo.Product p 
    WHERE (NOT p.ProductID IN (SELECT [KEY] FROM FREETEXTTABLE(dbo.Product, *, @search_term)))
    AND   (p.Name LIKE '%' + @search_term + '%')
    ORDER BY p.Popularity DESC
) AS results

这一切都有效,并且已经存在了一段时间。

现在这是棘手的部分。我最近发现这是网站上更昂贵的查询之一。我查看了查询计划,发现查询的 LIKE '%%' 部分会产生 50-80% 的成本。这真的不是什么大惊喜,因为通配符搜索往往很慢。问题是当前半部分本身返回足够的行时,UNION ALL 的后半部分不需要运行。

当前半部分(全文搜索)返回我需要的所有行时,有没有办法不执行 UNION ALL?

4

2 回答 2

3

你可以这样做:

SELECT TOP (@top) ..., ft.[RANK] * p.Popularity INTO #foo ... <FT query>;

IF @@ROWCOUNT < @top
  INSERT #foo SELECT TOP (@top) ..., p.Popularity FROM <like query>;

SELECT TOP (@top) ... FROM #foo ORDER BY Popularity DESC;

它的 I/O 多一点,但可能值得补偿。

您也可以考虑仅将第一个查询返回给客户端,并仅在第一个查询不够的情况下返回第二个结果集,并使应用程序足够智能以合并结果集。这只有在仅按 p.Popularity 排名的任何结果之前显示 ft.[RANK] * p.Popularity 时才有效。

于 2012-06-29T14:03:22.380 回答
0

我不知道您可以在单个语句中执行此操作的方法,但是您可以@@rowcount在第一个查询之后进行检查,如果它不够高,则仅触发第二个查询

于 2012-06-29T14:03:44.470 回答