Sql server 2008 如何使用TOP并有条件地忽略一个UNION ALL?

Sql server 2008 如何使用TOP并有条件地忽略一个UNION ALL?,sql-server-2008,tsql,optimization,Sql Server 2008,Tsql,Optimization,我正在查询一个包含用户搜索顶部结果全文索引的表,然后将通配符搜索的结果附加到该表的末尾 这是我的稍微简化的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 =

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

这是我的稍微简化的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
这一切都起作用,并且已经存在了一段时间

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


当全文搜索的前半部分返回我需要的所有行时,是否有一种方法不执行UNION ALL?

您可以这样做:

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.受欢迎程度排名之前显示ft.[RANK]*p.受欢迎程度的情况下才会起作用。

我不知道有哪种方法可以在一句话中做到这一点,但您可以在第一个查询后检查@@rowcount,只有在第二个查询不够高时才触发它

可以将结果集存储到临时表中,如果@@rowcount<@top,则使用LIKE%%query联合所有查询,否则返回临时表。也就是说,我还没有测试以确保该活动更有效,这就是为什么这是一个评论而不是答案。那么,我想我的评论是正确的,呵呵。很高兴看到一个与我有限的SQL经验猜测相符的答案。谢谢。这正是我所怀疑的。我用我的搜索样本进行了尝试,这种方法的读取次数大约高出10%。CPU使用量大致相同,持续时间也大致相同。因此,我的原始查询似乎是我现在应该坚持的。尽管如此,我还是会接受这个答案,因为它肯定是有帮助的。我的最后一段可能也需要一些测试。在第一个查询满足@top的情况下,它肯定会消耗更少的资源,但它需要对应用程序逻辑进行一些更改。尽管如此,我只是查看了一个更大的时间窗口,发现有4个查询比这个查询更昂贵。所以我应该首先关注这些。再次感谢。