개발자 한분이 문의를 했습니다.나도 개발자였는데... ㅠㅠ클러스터드 인덱스가 잡혀 있는데 delete 하려니까 시간이 너무 걸려요. 아마도 누군가가 트랜젝션을 걸고 테이블을 수정한 후 트랜젝션을 종료하지 않아서 또는 잠금이 오래 지속되어서 대기 상태일 것같았습니다. 그러면 어떤 세션이 어떤 세션에 의해 블로킹을 당했는지 알려면 어떻게 해야 할까요? sys.sysprocesses테이블을 이용한다면 blocked열을 sys.dm_exec_requests뷰를 이용한다면 blocking_session_id열을 참조하면 됩니다. 근데 이 사건이 굉장이 복잡하다면?? 예를 들어서 1번세션때문에 2번이 블로킹, 2번 세션 때문에 3번세션이 블로킹, ...99번 세션때문에...줄줄이 추적해 나가기가 힘들겠죠. 그래서 CTE를 이용해 블로킹 트리를 한번에 조회하는 쿼리를 작성해보았습니다.;WITH BlockProcesses (session_id, block_tree) AS ( SELECT A.blocking_session_id, block_tree = CONVERT(VARCHAR(1000), A.blocking_session_id) FROM sys.dm_exec_requests A LEFT OUTER JOIN sys.dm_exec_requests B ON A.blocking_session_id = B.session_id WHERE A.blocking_session_id > 0 AND B.session_id IS NULL UNION ALL SELECT A.session_id, block_tree = CONVERT(VARCHAR(1000), B.block_tree + '>' + CONVERT(VARCHAR(10), A.session_id)) FROM sys.dm_exec_requests A INNER JOIN BlockProcesses B ON A.blocking_session_id = B.session_id) SELECT DISTINCT A.session_id , Z.block_tree , text = ISNULL(ISNULL(CONVERT(VARCHAR(MAX), object_name(D.objectid, D.dbid)), D.text),'DBCC INPUTBUFFER(' + CONVERT(VARCHAR(10), A.session_id) + ')') , D.objectid , dbname = db_name(D.dbid) , D.dbid , A.status , A.cpu_time , A.memory_usage , A.total_scheduled_time , A.total_elapsed_time , A.last_request_start_time , A.last_request_end_time , worker_time = DATEDIFF(SECOND, A.last_request_start_time, CASE WHEN A.status = 'running' THEN GETDATE() ELSE A.last_request_end_time END) , completion_time = C.estimated_completion_time / 1000.0 , C.percent_complete , A.reads , A.writes , A.logical_reads , transaction_isolation_level = CASE A.transaction_isolation_level WHEN 0 THEN '0' WHEN 1 THEN '1 - READ UNCOMMITTED' WHEN 2 THEN '2 - READ COMMITTED' WHEN 3 THEN '3 - REPEATABLE READ' WHEN 4 THEN '4 - SERIALIZABLE' WHEN 5 THEN '5 - SNAPSHOT' END , A.lock_timeout , A.deadlock_priority , A.row_count , A.prev_error , B.num_reads , B.num_writes , B.last_read , B.last_write , B.net_packet_size , C.command , C.blocking_session_id , C.wait_type , C.wait_time , C.last_wait_type , C.wait_resource , C.granted_query_memory , A.host_name , A.program_name , A.client_interface_name , A.login_name , B.client_net_address FROM sys.dm_exec_sessions A LEFT OUTER JOIN sys.dm_exec_connections B ON A.session_id = B.session_id LEFT OUTER JOIN sys.dm_exec_requests C ON A.session_id = C.session_id OUTER APPLY sys.dm_exec_sql_text(B.most_recent_sql_handle) D INNER JOIN BlockProcesses Z ON A.session_id = Z.session_id ORDER BY Z.block_tree테스트를 위해 다음과 같은 상황을 가정해보았습니다.--* 첫번째 세션: BEGIN TRAN DROP TABLE TBL1 --* 두번째 세션: BEGIN TRAN SELECT * FROM TBL1 --* 세번째 세션: BEGIN TRAN SELECT * FROM TBL1첫번째 세션에서 시작한 트랜잭션이 아직 끝나지 않았기 때문에 두번째 세션에서의 SELECT는 블로킹 당할 것입니다. 세번째 세션도 두번째 세션때문에 블로킹 당할것입니다. 쿼리의 실행 결과는 다음과 같습니다. 1509세션이 원흉임을 쉽게 알 수 있습니다.
2014년 4월 29일 화요일
블로킹 세션 조회하기
피드 구독하기:
댓글 (Atom)
댓글 없음:
댓글 쓰기