sql-server-2008 - 如何使用 TOP 并有条件地忽略 UNION ALL?

标签 sql-server-2008 t-sql 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 = 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?

最佳答案

你可以这样做:

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 时,此功能才有效。

关于sql-server-2008 - 如何使用 TOP 并有条件地忽略 UNION ALL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11263171/

相关文章:

sql - 在函数 (SQL Server) 中执行动态 sql 时出现错误?

c# - 为什么完整的图像路径没有存储在数据库中?

performance - 如何构建有效的 SQL 过滤器?

sql-server - 将 TSQL 中的字符串处理为带时区的日期时间

sql-server - 如何在 SQL 中检查特定登录名下是否存在某个用户?

使用循环变量条件的 C 循环优化

sql - 我如何正确地装框这个校对?

sql - 有没有更好的方法来编写这个查询?

php - 为什么这些查询这么慢?

c - 这是 Clang 优化器错误还是未定义的行为?