0

该系统是多年前在 SQL7 中构建的,目前在 SQL2k5 中运行

我们有一个表 tProducts,它的 PK/Clustered Index 为自豪ctid Guid。我意识到为了获得最佳性能,我们应该修改表格,但目前不可能。我将它加入到 tProductSpecial 表中,该表还具有 productid 的 PK/Clustered Index,这也是这种关系中的 FK。我们在 tProducts 表中有大约 50k 条记录,在 tProductSpecial 表中有大约 35k 条记录(有些产品有特殊信息,有些没有)。还有一块。我在存储过程中使用临时表来获取登录的用户安全角色并加载它们,这也加入了 tProducts 表,roleid 是 tProducts 中的非聚集索引。我已经包含了一些访问这些表的 WHERE 条件。

SELECT *
FROM tProducts
  JOIN tProductSpecial ON tProducts.productid=tProductSpecial.productid
  JOIN #tRoles ON tProducts.roleid=#tRoles.roleid
WHERE
  (tProducts.productSKU = @sku AND tProducts.productStatus=1)  --DIRECT MATCH
  OR
  (  -- KEYWORD SEARCH
    CONTAINS(tProducts.*,'FORMSOF(INFLECTIONAL,''' + @lookuptext + ''')') 
    AND
    (
      @productStatus IS NULL
      OR
      (
        @productStatus IS NOT NULL
        AND
        tProducts.productStatus = @productStatus
      )          
    )
    AND 
    (  --- item on sale
      @bOnSale IS NULL
      OR @bOnSale=0
      OR
      (
        @bOnSale = 1
        AND tProducts.productOnSale=1
      )
    )
    AND
    (  -- from price
      @from=0 
      OR @from IS NULL
      OR 
      (
        @from<>0
        AND             
        tProducts.customerCost>=@from
      )         
    )
    AND
    (  --to price
      @to=0 
      OR @to IS NULL
      OR 
      (
        @to<>0
        AND             
        tProducts.customerCost<=@from
      )         
    )
    AND
    (  --how old is product
      @age IS NULL 
      OR @age = 0       
      OR
      (
        @age IS NOT NULL
        AND @age > 0
        AND DATEDIFF(day,tProducts.productCreated,GETDATE()) 
          <=CONVERT(varchar(10),@age)       
       )
     )

  ORDER BY tProducts.productSKU
4

2 回答 2

2

问题可能是由于参数嗅探造成的——即使参数不同,您也一遍又一遍地使用相同的计划,而且只有有时扫描才是最好的方法。在 SQL Server 2008 中,您可以简单地添加OPTION (RECOMPILE)or OPTIMIZE FOR UNKNOWN,但在 SQL Server 2005 中,尝试更改存储过程并添加WITH RECOMPILE选项。这将强制 SQL Server 根据传入的参数每次都考虑一个新计划。

另一种选择是根据是否填充等来@bOnSale动态构建查询。@from在 2005 年,这将导致计划缓存膨胀,但总体而言您可能会过得更好。这可以完全避免全文访问,例如在@sku填充时。同样,在 SQL Server 2008 中这会更好,因为您可以使用Optimize for ad hoc workloads.

于 2013-08-22T21:22:22.850 回答
0

一个长期存在的存储过程可能会由于各种原因突然发展出计划不佳的情况。就在我的脑海中,这里有一些突出的:

索引更改

删除/修改表上的索引可能会导致多年来具有完美执行计划的查询向南走。解决方案:不要那样做。如果您打算这样做,请检查该表上的依赖关系,并确保所有内容仍处于良好的执行计划中。

表统计

由于多种原因,索引统计信息可能会被弄乱。例如,将大量数据加载到存储过程所引用的表中可能会混淆该表上的索引统计信息,从而误导查询优化器构建一个糟糕的执行计划。解决方案包括以下一项或多项:

  • 更新所涉及表的统计信息
  • 运行DBCC FREEPROCCACHE以刷新存储过程缓存。
  • sp_recompile在有问题的存储过程上执行。

直接引用存储过程参数

存储过程的查询直接使用传递给存储过程的参数,在创建和缓存计划时,根据存储过程第一次执行时的参数值获取执行计划。如果这些参数值有点过分,缓存的执行计划可能会因为奇怪的原因而执行得很好,但对于一般情况来说却非常糟糕。短期解决方案是运行sp_recompile或修改存储过程,以便具有with recompile选项(但是请注意,这会对性能产生重大影响,因为每次执行都会重新编译存储过程。这意味着在编译过程中会使用编译锁,并且这可以(并且确实)导致阻塞。

解决此问题的正确方法是在存储过程中声明一个局部变量并将其设置为参数的值。这会将参数值转换为表达式并打破计划对参数值的依赖。我第一次遇到这个问题时让我感到震惊。

祝你好运!

于 2013-08-22T23:25:51.057 回答