spid 상태가 일시 중지된 이유를 확인하는 방법은 무엇입니까?spid가 어떤 리소스를 기다리고 있나요?
-
21-12-2019 - |
문제
난 달린다 EXEC sp_who2 78
그리고 나는 다음을 얻습니다 결과:
상태가 정지된 이유를 어떻게 알 수 있나요?
이 과정은 무겁다 INSERT
비용이 많이 드는 쿼리를 기반으로 합니다.큰 SELECT
여러 테이블에서 데이터를 가져와서 다른 테이블에 약 3~4백만 개의 행을 쓰는 것입니다.
잠금/블록이 없습니다.
그만큼 waittype
그것은 에 연결되어 있습니다 CXPACKET
.아래 사진에서 볼 수 있듯이 78이 9개 있기 때문에 이해할 수 있습니다.
제가 우려하는 점과 제가 정말로 알고 싶은 점은 왜 1위가 되는지 입니다. SPID
78은 정지되었습니다.
나는 다음과 같은 상황을 이해합니다. 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일 수 있고, WAIT는 네트워크 통신일 수도 있고, 잠금이나 래치를 기다리는 것일 수도 있습니다.대기 중인 작업이 완료되면 활성화됩니다.예를 들어 쿼리가 전체 테이블 tblStudents의 데이터를 읽기 위한 I/O 요청을 게시한 경우 이 작업은 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