对于我们的一位客户,我们的应用程序遇到了一些性能问题。这是一个.NET 3.5 Web应用程序,正在使用和更新SQL Server数据库上的数据。当前,我们的生产环境由一台Windows 2008 R2计算机作为前端,而在后端则是一个SQL Server 2008 R2群集。我们的应用程序使用COM +和MSDTC连接到数据库。
这是正在发生的事情:我们的最终用户有时会抱怨应用程序运行缓慢。某些页面的加载时间比预期的要多。在尝试找出正在发生的事情时,我设法找出了数据库方面的一些奇怪行为,这可能是性能下降的原因。我注意到有时有些SQL语句需要花费更多的时间才能运行。我设法使用探查器跟踪(带有TSQL_Duration模板)来识别长时间运行的查询,从而识别其中一些语句(主要是对应用程序存储过程的调用)。
问题是,当我直接在SQL Management Studio的数据库上运行这些存储过程时,有时它们会花费很长时间(大约7/8秒),而其他时候它们却很快(不到1秒)。我不知道为什么会这样,这让我发疯,因为其他任何应用程序都没有使用SQL机器(4核,32 GB),并且这些查询的运行时间不会太长。
不是DBA或SQL Server专家,我一直在尝试研究一些可以帮助我理解问题的东西。这是我尝试解决问题以及到目前为止发现的步骤:
- 应用程序调用的所有TSQL代码都是在存储过程中编写的。
- 我在SQL Server事件探查器上确定了一些长时间运行的查询,但是,当我在Management Studio上运行这些查询时,它们要么运行很长时间(从4到10秒),要么运行很快(不到1秒)。我正在使用参数中传递的相同数据运行完全相同的查询。这些查询主要是存储过程,其中包含选择语句。
- 我尝试查看等待和排队统计信息,以尝试确定是否有某些资源在等待进程。我运行了以下查询:
WITH Waits AS
(SELECT
wait_type,
wait_time_ms / 1000.0 AS WaitS,
(wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
signal_wait_time_ms / 1000.0 AS SignalS,
waiting_tasks_count AS WaitCount,
100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT', 'BROKER_TO_FLUSH',
'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE',
'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
)
SELECT
W1.wait_type AS WaitType,
CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
W1.WaitCount AS WaitCount,
CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount, W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO
这是我发现的:
- 在我使用DBCC SQLPERF重置统计信息后(大约1或2小时后),我最等待的等待类型是SOS_SCHEDULER_YIELD和WRITELOG
- 随着时间的推移(执行大约1天后),即使每种数据库的平均等待时间不长,在数据库上发生最多的等待类型还是CXPACKET(67%)和OLEDB(17%)。我还注意到,SQL Profiler上标识的运行时间更长的语句是对存储过程的调用,这些存储过程返回多个结果集(通常为3个)。这里会出现并列问题吗?有什么方法可以尝试确定这是否是问题的原因?
- 我读过某个地方,OLEDB等待可能是由对链接服务器等OLEDB资源的调用引起的。我们确实有一个链接服务器与Indexing Services计算机(MSIDXS)连接,但是没有一个被确定为长时间运行的语句都使用该链接服务器。
- 对于LCK_M_X类型的等待,我有更高的平均等待时间(平均约1.5秒),但是与其他类型的等待相比,这些等待类型却很少发生(例如,64 LCK_M_X等待与10,823 CXPACKET在同一时间等待)。
- 我注意到的一件事是MSDTC服务不是群集的。SQL Server服务是群集的,但不是MSDTC的。是否可以因此而对性能产生影响?我们之所以使用MSDTC,是因为我们的应用程序使用企业服务(DCOM)来访问数据库,但是服务器不是由我们而是由客户端安装和配置的。
谁能帮助我进一步了解这些数据?谁能帮助我了解可能发生的事情?我可以在服务器上做一些事情来尝试解决问题吗?我应该与应用程序开发团队联系吗?
exec()
功能可以解释观察到的行为。在这种情况下,sp_executesql
通常可以使用动态SQL语句解决问题。