我们的数据库中有一个函数,它搜索两个大表以查看是否存在值。这是一个非常大的查询,但它被优化为使用索引,并且通常运行得非常快。
在过去的两周内,这个功能已经三次失败,并且运行速度非常慢,导致死机和性能不佳。即使在低于使用峰值的时候也会发生这种情况。
使用SQL Server中的“Alter Function”重建函数似乎可以解决这个问题。一旦我们这样做,服务器使用率就会恢复正常,一切正常。
这使我们认为函数查询计划已经重建,并且正在考虑正确的索引,但我们不知道为什么SQL Server决定突然将查询计划更改为更糟糕的计划。
有没有人有什么想法可能会导致这种行为,或者如何测试它或阻止它?我们正在运行SQL Server 2008 Enterprise。
答案 0 :(得分:5)
您所描述的行为通常是由于错误缓存的查询计划和/或过时的统计信息。
当WHERE子句中有大量参数时,通常会发生这种情况,特别是那些形式为的长列表:
(@parameter1 is NULL OR TableColumn1 = @parameter1)
比如说,缓存的查询计划到期,并且使用不具代表性的参数集调用proc。然后为该数据配置文件缓存该计划。但是,如果过程通常与一组非常不同的参数相同,则该计划可能不合适。这通常被称为“参数嗅探”。
有一些方法可以缓解并消除此问题,但它们可能需要权衡取决于您的SQL Server版本。查看OPTIMIZE FOR
和OPTIMIZE FOR UNKNOWN
。 IF(并且它是一个很大的if)proc很少被调用但是必须尽可能快地运行你可以将它标记为OPTION(RECOMPILE)
,每次调用它时强制重新编译,但是不要经常调用它无需调查即可进行OR。
[注意:请注意您的SQL Server 2008框中有Service pack and Cumulative Update (CU),因为重新编译和参数嗅探逻辑在某些版本中的工作方式不同]
运行此查询(来自Glenn Berry)以确定统计状态:
-- When were Statistics last updated on all indexes?
SELECT o.name, i.name AS [Index Name],
STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date],
s.auto_created, s.no_recompute, s.user_created, st.row_count
FROM sys.objects AS o WITH (NOLOCK)
INNER JOIN sys.indexes AS i WITH (NOLOCK)
ON o.[object_id] = i.[object_id]
INNER JOIN sys.stats AS s WITH (NOLOCK)
ON i.[object_id] = s.[object_id]
AND i.index_id = s.stats_id
INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK)
ON o.[object_id] = st.[object_id]
AND i.[index_id] = st.[index_id]
WHERE o.[type] = 'U'
ORDER BY STATS_DATE(i.[object_id], i.index_id) ASC OPTION (RECOMPILE);