这个系统是几年前在SQL7中构建的,目前在SQL2k5中运行
我们有一个表格产品,其中包含一个骄傲的Guid作为PK / Clustered Index。我意识到为了获得最佳性能,我们应该修改表格,但此时不可能。我将它加入到tProductSpecial表中,该表还有一个PK / Clustered Index of productid,这也是这种关系中的FK。我们在tProducts表中有大约50k记录,在tProductSpecial表中有大约35k记录(一些产品有特殊信息,有些没有)。还有一件。我在sproc中使用临时表来获取登录用户安全角色并加载它们,这也加入了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
答案 0 :(得分:2)
问题可能是由于参数嗅探 - 即使参数不同,你也会一遍又一遍地使用相同的计划,有时只扫描是最好的方法。在SQL Server 2008中,您只需添加OPTION (RECOMPILE)
或OPTIMIZE FOR UNKNOWN
,但在SQL Server 2005中,请尝试更改存储过程并添加WITH RECOMPILE
选项。这将迫使SQL Server每次都根据传入的参数考虑新的计划。
另一种选择是根据是否填充@bOnSale
,@from
等动态建立查询。在2005年,这将导致计划缓存膨胀,但总体而言你可能会更好。这可以完全避免全文访问,例如,填充@sku
时。同样,在SQL Server 2008中,这样做会更好,因为您可以使用Optimize for ad hoc workloads
来避免某些计划缓存膨胀。
答案 1 :(得分:0)
长期存储的程序可能会因各种原因而突然发展出一个糟糕的计划案例。在我的头顶,有一些突出:
索引更改
删除/修改表上的索引可能会导致具有完美罚款执行计划多年的查询向南移动。解决方案:不要这样做。如果您要这样做,请检查该表的依赖关系,并确保所有内容仍然是一个良好的执行计划。
表统计
由于多种原因,索引统计数据可能会被污染。例如,存储过程引用的表中的大量数据加载可以对该表的索引统计信息进行大量提升,从而误导查询优化器构建不良的执行计划。解决方案包括以下一项或多项:
DBCC FREEPROCCACHE
以刷新存储过程缓存。sp_recompile
。直接引用存储过程参数
在创建和缓存计划时,其查询直接使用传递到存储过程的参数的存储过程将根据存储过程首次执行时参数的值获取执行计划。如果这些参数值有点outré,则缓存的执行计划可能对奇怪的原因表现良好,但对于一般情况则非常差。短期解决方案是torun sp_recompile
或修改存储过程以便具有with recompile
选项(注意,这会对性能产生重大影响,因为存储过程会在每次执行时重新编译。这意味着在编译过程中会进行编译锁定,这会导致阻塞。
此问题的正确解决方法是在存储过程中声明局部变量并将其设置为参数的值。这会将参数值转换为表达式,并破坏计划对参数值的依赖性。我第一次遇到这个问题时就把我弄坏了。
祝你好运!