为什么这个SQL语句很慢?

时间:2009-08-18 05:32:57

标签: sql sql-server

我有一张包含大约100万条记录的表(运行SQL Server 2008 Web)。我有一个搜索例程,试图匹配产品代码和产品描述。 但是在某些情况下它很慢。下面是(cut-down)sql语句:

WITH AllProducts AS (
  SELECT       p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
  FROM        Product AS p 
    WHERE p.IsEnabled=1 AND
    (
      p.BaseSku = 'KPK-3020QWC-C' -- this on its own is fast
      OR
      CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') -- and this on its own is fast, but not both
    )
) SELECT * FROM AllProducts        
  WHERE RowNumber BETWEEN 1 AND 20;

请注意,如果我只是在[p.BaseSku ='KPK-3020QWC-C']或[CONTAINS(p.FreeTextStrings,'“KPK-3020QWC *”')上单独(但不是两者)比较它的瞬间。如果我将它们进行比较,则需要很长时间(几分钟) - 并且只返回一行。

IsEnabled和BaseSku被编入索引,FreeTextStrings被FTS索引。

我记得这一切都很好。

有人可以对此有所了解并提出一些解决方案吗?

执行计划文件可在此处获取:http://wiki.webgear.co.nz/GetFile.aspx?File=Temp%5cSearch%20Test.sqlplan.zip

3 个答案:

答案 0 :(得分:10)

or在SQL Server上出了名的慢。至少可以说,这是加重的。

尝试使用union

将其拆分为两个查询
WITH AllProducts AS (
  select *, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
  from (
  SELECT       p.*
  FROM        Product AS p 
    WHERE p.IsEnabled=1 AND
      p.BaseSku = 'KPK-3020QWC-C' 
  UNION
  SELECT       p.*
  FROM        Product AS p 
    WHERE p.IsEnabled=1 AND
      CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"')
  )
) SELECT * FROM AllProducts        
  WHERE RowNumber BETWEEN 1 AND 20;

答案 1 :(得分:1)

这似乎运作良好:

WITH AllProducts AS (
  SELECT       p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
  FROM        Product AS p 
    WHERE p.IsEnabled=1 AND
    (
      CONTAINS(p.BaseSku, 'KPK-3020QWC-C') /* instead of p.BaseSku = 'KPK-3020QWC-C' */
      OR
      CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"')
    )
) SELECT * FROM AllProducts        
  WHERE RowNumber BETWEEN 1 AND 20;

(我已经有BaseSku FTS索引)

答案 2 :(得分:0)

Make sure all necessary indexes are in place.我在其中一个查询中遇到了or子句的相同问题,并且使用INCLUDE列创建了一个NONCLUSTERED INDEX来修复性能。

经过进一步测试后,索引的 INCLUDE列部分确实解决了性能问题。以下是我为确定问题以及如何解决问题所做的工作:

使用执行计划来帮助您创建缺失的索引:

如果没有索引,那么当它应该在几毫秒内运行时,查询需要2+分钟。因此,我在SSMS中使用和不使用or子句来比较查询的执行计划,并且我不需要做什么(主要是由于我对执行计划缺乏了解)。

但是如果你在绿色文本中查看执行计划,SSMS可能会告诉你创建一个非聚集索引。嗯......值得一试。所以我创建了索引并解决了问题!您可以右键单击"创建索引"查询并选择"缺少索引详细信息..."。这将打开一个新选项卡,其中包含您要运行的完整查询。只要给它一个名字。