【问题标题】:Slow SQL query involving CONTAINS and OR涉及 CONTAINS 和 OR 的慢速 SQL 查询
【发布时间】:2011-06-30 11:54:17
【问题描述】:

我们遇到了一个问题,希望 Stack Overflow 的好心人能帮我们解决。我们正在运行 SQL Server 2008 R2,并且遇到了一个查询问题,该查询需要很长时间才能在中等数据集(大约 100000 行)上运行。我们使用 CONTAINS 来搜索 xml 文件并在另一列上使用 LIKE 来支持前导通配符。

我们通过以下运行大约 35 秒的小查询重现了该问题:

SELECT something FROM table1 
WHERE (CONTAINS(TextColumn, '"WhatEver"') OR  
        DescriptionColumn LIKE '%WhatEver%')

查询计划:

如果我们将上面的查询修改为使用 UNION,运行时间会从 35 秒下降到

SELECT something FROM table1 WHERE (CONTAINS(TextColumn, '"WhatEver"') 
UNION
(SELECT something FROM table1 WHERE (DescriptionColumn LIKE '%WhatEver%'))

查询计划:

我们使用 CONTAINS 搜索的列是类型为 image 的列,由大小在 1k 到 20k 之间的任何 xml 文件组成。

对于为什么第一个查询如此缓慢,我们没有好的理论,所以我们希望这里有人能就此事发表一些明智的看法。据我们所知,查询计划没有显示任何异常。我们还重建了索引和统计信息。

我们在这里忽略了什么明显的东西吗?

提前感谢您的宝贵时间!

【问题讨论】:

  • 你试过改变where子句的顺序吗?
  • 是的,我们已经尝试过了。性能方面没有可衡量的差异。
  • 你能分别运行这两个查询吗?哪个更慢?
  • 我们能看到两个查询计划吗?每个查询返回多少行?
  • 这两个版本会产生不同的执行计划吗?

标签: sql performance sql-server-2008


【解决方案1】:

您为什么使用DescriptionColumn LIKE '%WhatEver%' 而不是CONTAINS(DescriptionColumn, '"WhatEver"')

CONTAINS 显然是全文谓词,将使用 SQL Server 全文引擎过滤搜索结果,但 LIKE 是“普通”SQL Server 关键字,因此 SQL Server 不会使用 Full - 辅助此查询的文本引擎 - 在这种情况下,因为 LIKE 术语以通配符开头,SQL Server 将无法使用任何索引来帮助查询,这很可能导致表扫描和/或更差性能优于使用全文引擎。

如果没有执行计划,它的 困难 是无法判断的,但是我对发生的事情的猜测是:

  • 查询的UNION 变体正在对table1 执行表扫描 - 表扫描并不快,但是由于表中的行相对较少,它没有执行 /em> 缓慢(与 35 秒的基准相比)。

  • 在查询的OR 变体中,SQL Server 首先使用全文引擎根据CONTAINS 进行过滤,然后继续对结果中的每个匹配行执行 RDI 查找以基于LIKE 谓词的过滤器,但是由于某种原因,SQL Server 大大低估了行数(这可能发生在某些类型的谓词中),因此继续执行数以千计的 RDI 查找,结果非常慢(a表扫描会更快)。

要真正了解发生了什么,您需要制定一个查询计划。

【讨论】:

  • 我们使用 LIKE 搜索“DescriptionColumn”的原因是在搜索时允许使用前导通配符。我很抱歉没有在原始问题中提及这一点。查询计划已添加到原始帖子中。
  • LIKE 是与问题无关的原始查询。您可以改为OR SomeNumberColumnCoveredByAnIndex = 69,但性能仍然下降。它正在执行聚集索引扫描的事实并非如此,因为DescriptionColumn 正在使用%value% 进行查询;一旦出现OR,服务器就会切换到聚集索引扫描——即使数字列被索引查询单值相等(例如DescriptionID = 7)所覆盖
【解决方案2】:

你们有没有试过这个:

SELECT *
FROM table
WHERE CONTAINS((column1, column2, column3), '"*keyword*"')  

而不是这个:

SELECT *
FROM table
WHERE CONTAINS(column1, '"*keyword*"') 
OR CONTAINS(column2, '"*keyword*"') 
OR CONTAINS(column3y, '"*keyword*"') 

第一个要快很多。

【讨论】:

    【解决方案3】:

    我刚碰到这个。据报道,这是 SQL Server 2008 R2 上的一个错误:

    http://www.arcomit.co.uk/support/kb.aspx?kbid=000060

    您使用两个选择的 UNION 而不是 OR 的方法是他们在那篇文章中推荐的解决方法。

    【讨论】:

      猜你喜欢
      • 2016-07-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-09
      相关资源
      最近更新 更多