如何找出 spid 状态暂停的原因?spid 正在等待什么资源?
-
21-12-2019 - |
题
我跑 EXEC sp_who2 78
我得到以下结果 结果:
我怎样才能找到其状态被暂停的原因?
这个过程是一个重 INSERT
基于昂贵的查询。一个大的 SELECT
从多个表获取数据并将大约 3-4 百万行写入另一个表。
没有锁/块。
这 waittype
它链接到的是 CXPACKET
. 。我可以理解,因为有 9 个 78,如下图所示。
我关心的是,我真正想知道的是为什么数字 1 SPID
78号被暂停。
我明白,当a的状态 SPID
被挂起意味着进程正在等待资源,当它获得资源时它将恢复。
我如何才能找到有关此内容的更多详细信息?什么资源?为什么不可用?
我经常使用下面的代码及其变体,但是我还能做些什么来找出为什么 SPID
被暂停?
select *
from sys.dm_exec_requests r
join sys.dm_os_tasks t on r.session_id = t.session_id
where r.session_id = 78
我已经用过 sp_whoisactive. 。我针对这个特定的 spid78 得到的结果如下:(为了适合屏幕分成3张图片)
解决方案
暂停:这意味着请求当前不活动,因为它正在等待资源。该资源可以是用于读取页面的 I/O,WAITit 可以是网络上的通信,或者它正在等待锁定或闩锁。一旦它正在等待的任务完成,它将变得活跃。例如,如果查询发出了一个 I/O 请求来读取完整表 tblStudents 的数据,那么该任务将被挂起,直到 I/O 完成。一旦 I/O 完成(表 tblStudents 的数据在内存中可用),查询将移至 RUNNABLE 队列。
因此,如果正在等待,请检查 wait_type 列以了解其在等待什么,并根据 wait_time 进行故障排除。
我开发了以下过程来帮助我解决此问题,其中包括 WAIT_TYPE。
use master
go
CREATE PROCEDURE [dbo].[sp_radhe]
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT es.session_id AS session_id
,COALESCE(es.original_login_name, '') AS login_name
,COALESCE(es.host_name,'') AS hostname
,COALESCE(es.last_request_end_time,es.last_request_start_time) AS last_batch
,es.status
,COALESCE(er.blocking_session_id,0) AS blocked_by
,COALESCE(er.wait_type,'MISCELLANEOUS') AS waittype
,COALESCE(er.wait_time,0) AS waittime
,COALESCE(er.last_wait_type,'MISCELLANEOUS') AS lastwaittype
,COALESCE(er.wait_resource,'') AS waitresource
,coalesce(db_name(er.database_id),'No Info') as dbid
,COALESCE(er.command,'AWAITING COMMAND') AS cmd
,sql_text=st.text
,transaction_isolation =
CASE es.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END
,COALESCE(es.cpu_time,0)
+ COALESCE(er.cpu_time,0) AS cpu
,COALESCE(es.reads,0)
+ COALESCE(es.writes,0)
+ COALESCE(er.reads,0)
+ COALESCE(er.writes,0) AS physical_io
,COALESCE(er.open_transaction_count,-1) AS open_tran
,COALESCE(es.program_name,'') AS program_name
,es.login_time
FROM sys.dm_exec_sessions es
LEFT OUTER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
LEFT OUTER JOIN sys.dm_exec_requests er ON es.session_id = er.session_id
LEFT OUTER JOIN sys.server_principals sp ON es.security_id = sp.sid
LEFT OUTER JOIN sys.dm_os_tasks ota ON es.session_id = ota.session_id
LEFT OUTER JOIN sys.dm_os_threads oth ON ota.worker_address = oth.worker_address
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS st
where es.is_user_process = 1
and es.session_id <> @@spid
ORDER BY es.session_id
end
下面的这个查询还可以显示基本信息,以在 spid 挂起时提供帮助,通过显示 spid 正在等待哪个资源。
SELECT wt.session_id,
ot.task_state,
wt.wait_type,
wt.wait_duration_ms,
wt.blocking_session_id,
wt.resource_description,
es.[host_name],
es.[program_name]
FROM sys.dm_os_waiting_tasks wt
INNER JOIN sys.dm_os_tasks ot ON ot.task_address = wt.waiting_task_address
INNER JOIN sys.dm_exec_sessions es ON es.session_id = wt.session_id
WHERE es.is_user_process = 1
请参见下图作为示例:
其他提示
我使用 sp_whoIsActive 来查看此类信息,因为它是一个现成的免费工具,可为您提供解决缓慢查询问题的良好信息:
如何使用 sp_WhoIsActive 查找慢 SQL Server 查询
通过这个,您可以获得查询文本、它正在使用的计划、查询正在等待的资源、什么正在阻塞它、它正在取出什么锁等等。
比尝试自己推出要容易得多。
您可以通过以下方式解决:
- 修复簇索引。
- 使用时态表获取所有表的一部分并使用它。
我对一个有 400,000,000 行的表也有同样的问题,并使用临时表来获取其中的一部分,然后我使用我的过滤器和内部结构,因为更改索引不是一个选项。
一些例子:
--
--this is need be cause DECLARE @TEMPORAL are not well for a lot of data.
CREATE TABLE #TEMPORAL
(
ID BIGINT,
ID2 BIGINT,
DATA1 DECIMAL,
DATA2 DECIMAL
);
WITH TABLE1 AS
(
SELECT
L.ID,
L.ID2,
L.DATA
FROM LARGEDATA L
WHERE L.ID = 1
), WITH TABLE2 AS
(
SELECT
L.ID,
L.ID2,
L.DATA
FROM LARGEDATA L
WHERE L.ID = 2
) INSERT INTO #TEMPORAL SELECT
T1.ID,
T2.ID,
T1.DATA,
T2.DATA
FROM TABLE1 T1
INNER JOIN TABLE2 T2
ON T2.ID2 = T2.ID2;
--
--this take a lot of resources proces and time and be come a status suspend, this why i need a temporal table.
SELECT
*
FROM #TEMPORAL T
WHERE T.DATA1 < T.DATA2
--
--IMPORTANT DROP THE TABLE.
DROP TABLE #TEMPORAL