SQL Server에서 장시간 열려 있는 트랜잭션을 확인하는 SQL
公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13
結論
장시간 열려 있는 트랜잭션은 `sys.dm_tran_active_transactions`와 `sys.dm_tran_session_transactions`를 조인하여 `transaction_begin_time`이 오래된 순으로 정렬하면 특정할 수 있습니다. `sys.dm_exec_sessions`를 추가하면 어느 로그인·어느 애플리케이션이 원인인지까지 알 수 있습니다. 특정용 SQL은 참조 전용이지만, `KILL`에 의한 강제 종료는 롤백을 수반하는 고위험 작업입니다.
この文書の適用条件
| 対象製品 | SQL Server / Amazon RDS for SQL Server / Azure SQL Managed Instance |
|---|---|
| 確認バージョン | SQL Server 2008 이후 |
| 適用環境 | 온프레미스, EC2, Amazon RDS, Azure |
| 必要権限 | 참조용 SQL은 VIEW SERVER STATE. `DBCC OPENTRAN`은 sysadmin 또는 db_owner. `KILL`은 ALTER ANY CONNECTION(또는 processadmin / sysadmin) |
| 実行影響 | 참조용 SQL은 변경 없음. `KILL`은 세션을 강제 종료하고 미커밋 트랜잭션을 롤백합니다 |
| 再起動 | 불필요 |
| 最終検証日 | 2026-08-13 |
そのまま実行できるコマンド
- 対象
- SQL Server 2008 이후 / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- 없음(참조만)
- Production実行
- 가능
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
at.transaction_id,
at.name AS transaction_name,
at.transaction_begin_time,
DATEDIFF(SECOND, at.transaction_begin_time, GETDATE()) AS open_seconds,
at.transaction_type, -- 1:読み書き 2:読み取り専用 3:システム 4:分散
at.transaction_state, -- 2:アクティブ 3:終了(読み取り専用) 7:ロールバック中
st.session_id,
st.is_user_transaction,
st.open_transaction_count,
es.login_name,
es.host_name,
es.program_name,
es.status AS session_status,
es.last_request_start_time,
es.last_request_end_time,
ec.client_net_address,
ec.connect_time,
txt.text AS last_statement
FROM sys.dm_tran_active_transactions AS at
INNER JOIN sys.dm_tran_session_transactions AS st
ON at.transaction_id = st.transaction_id
LEFT JOIN sys.dm_exec_sessions AS es
ON st.session_id = es.session_id
LEFT JOIN sys.dm_exec_connections AS ec
ON st.session_id = ec.session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) AS txt
WHERE st.is_user_transaction = 1
ORDER BY at.transaction_begin_time ASC;`CROSS APPLY sys.dm_exec_sql_text(...)`로 하면 핸들을 가져올 수 없는 세션이 결과에서 빠집니다. 방치된 세션을 놓치지 않기 위해 여기서는 `OUTER APPLY`를 사용합니다. `session_status`가 sleeping이고 `open_transaction_count`가 1 이상인 세션이 전형적인 "BEGIN TRAN 방치"입니다.
- 対象
- SQL Server 2008 이후 / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- 없음(참조만)
- Production実行
- 가능
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT TOP (1)
at.transaction_id,
at.transaction_begin_time,
DATEDIFF(SECOND, at.transaction_begin_time, GETDATE()) AS open_seconds,
st.session_id,
st.open_transaction_count,
es.login_name,
es.host_name,
es.program_name,
es.status AS session_status
FROM sys.dm_tran_active_transactions AS at
INNER JOIN sys.dm_tran_session_transactions AS st
ON at.transaction_id = st.transaction_id
LEFT JOIN sys.dm_exec_sessions AS es
ON st.session_id = es.session_id
WHERE st.is_user_transaction = 1
ORDER BY at.transaction_begin_time ASC;트랜잭션 로그가 해제되지 않는(`log_reuse_wait_desc = ACTIVE_TRANSACTION`) 경우 가장 먼저 필요한 것이 이 "가장 오래된 트랜잭션"입니다. 이보다 뒤의 로그는 잘라낼 수 없습니다.
- 対象
- SQL Server 2008 이후 / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- 없음(참조만)
- Production実行
- 가능
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
r.session_id,
r.status,
r.command,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.cpu_time,
r.total_elapsed_time,
r.open_transaction_count,
r.percent_complete, -- ROLLBACK など一部の操作で進捗率が入る
SUBSTRING(
t.text,
(r.statement_start_offset / 2) + 1,
((CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(t.text)
ELSE r.statement_end_offset
END - r.statement_start_offset) / 2) + 1
) AS running_statement
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.session_id <> @@SPID
ORDER BY r.total_elapsed_time DESC;첫 번째 쿼리에서 찾아낸 세션이 "지금도 무언가를 실행 중인지, 실행을 마치고 트랜잭션만 열려 있는지"를 구분합니다. `status`가 running/suspended면 처리 중이고, `sys.dm_exec_requests`에 행이 없으면 처리는 끝났고 트랜잭션만 남아 있습니다.
- 対象
- SQL Server 2008 이후 / Amazon RDS for SQL Server
- 権限
- sysadmin 고정 서버 역할 또는 db_owner 고정 데이터베이스 역할
- 変更作業
- 없음(참조만)
- Production実行
- 가능
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: sysadmin または db_owner
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
USE [SampleDB];
GO
DBCC OPENTRAN;대상 데이터베이스의 가장 오래된 활성 트랜잭션과, 복제 미배포 트랜잭션 정보를 반환합니다. 열려 있는 트랜잭션이 없으면 "활성 오픈 트랜잭션이 없습니다"라는 취지의 메시지가 반환됩니다. DMV보다 정보량은 적지만 한 문장으로 상황을 파악할 수 있습니다.
- 対象
- SQL Server 2008 이후 / Amazon RDS for SQL Server
- 権限
- ALTER ANY CONNECTION, 또는 processadmin / sysadmin
- 変更作業
- 있음(세션을 강제 종료하고 미커밋 트랜잭션을 롤백)
- Production実行
- 원칙적으로 불가. 영향 범위를 확인하고 업무 측의 승인을 받은 후 실행
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: ALTER ANY CONNECTION / processadmin / sysadmin
-- 変更作業: あり(セッション強制終了 → 未コミットトランザクションのロールバック)
-- Production 実行: 原則不可。業務影響の確認と承認を得てから実行すること
-- 57 は前掲のクエリで特定した session_id に置き換える
KILL 57;
-- 既にロールバック中のセッションについて進捗率を確認する
KILL 57 WITH STATUSONLY;`KILL`은 롤백을 시작하기만 하며, 완료까지 걸리는 시간은 원래 트랜잭션이 수행한 변경량에 비례합니다. 장시간의 업데이트를 강제 종료하면 롤백에 그 이상의 시간이 걸릴 수 있습니다. `WITH STATUSONLY`는 이미 롤백 중인 세션에 대해서만 진행률을 반환합니다.
結果の読み方
| 列 | 意味 | 確認するポイント |
|---|---|---|
| transaction_begin_time | 트랜잭션 시작 시각 | 현재 시각과의 차이가 업무상 있을 수 없는 길이가 아닌지 |
| open_seconds | 열려 있는 시간(초, 산출값) | 수백 초~수 시간이면 방치일 가능성이 높음 |
| transaction_type | 1=읽기/쓰기 / 2=읽기 전용 / 3=시스템 / 4=분산 | 1과 4는 로그 해제를 막음. 2는 영향이 작음 |
| transaction_state | 2=활성 / 3=읽기 전용으로 종료 / 7=롤백 중 | 7이 계속되면 이미 롤백 처리 중이며, KILL을 반복해도 빨라지지 않음 |
| open_transaction_count | 해당 세션에서 열려 있는 트랜잭션 수 | 2 이상이면 중첩된 트랜잭션이 남아 있음 |
| session_status | 세션 상태(running / sleeping 등) | sleeping이면서 트랜잭션이 열려 있는 상태가 전형적인 방치 |
| program_name / host_name / login_name | 접속 원본 애플리케이션·호스트·로그인 | 어느 애플리케이션이 원인인지 특정. 수정 요청 대상 판단 자료가 됨 |
| last_statement | 해당 연결에서 마지막으로 실행된 SQL | BEGIN TRAN 이후 커밋이 없는 패턴인지 확인 |
| blocking_session_id | 블로킹 중인 세션 ID | 0이 아니면 블로킹 체인을 거슬러 올라감 |
こういう状況で使います
- 트랜잭션 로그가 해제되지 않고 `log_reuse_wait_desc`가 ACTIVE_TRANSACTION인 채로 변하지 않는다
- 특정 테이블에 대한 업데이트가 장시간 차단되어 타임아웃이 빈발한다
- 애플리케이션을 재시작하면 일시적으로 해소되지만 얼마 지나면 재발한다
- 잠금 대기 세션이 쌓여 연결 수가 상한에 가까워진다
考えられる原因(可能性の高い順)
01
애플리케이션이 BEGIN TRAN 이후 커밋/롤백을 수행하지 않음
예외 처리에서 커밋도 롤백도 지나가지 않는 경로가 있으면, 연결이 풀로 반환되어도 트랜잭션이 남습니다. `session_status`가 sleeping인데 트랜잭션이 열려 있는 상태로 관측됩니다.
02
대화형 도구에서 트랜잭션을 연 채로 방치
관리 도구에서 `BEGIN TRAN`을 실행한 채 화면을 닫지 않고 자리를 비운 경우입니다. `program_name`으로 판별할 수 있습니다.
03
대량 업데이트의 롤백이 진행 중
`transaction_state = 7`인 경우 이미 롤백 중입니다. 이 상태는 기다리는 것 외에 단축할 방법이 없으며, `KILL`을 반복해도 빨라지지 않습니다.
04
분산 트랜잭션이 미해결 상태로 남아 있음
`transaction_type = 4`인 분산 트랜잭션은 조정자(MS DTC) 쪽 상태에 의존합니다. 데이터베이스 쪽 조작만으로는 해소되지 않는 경우가 있습니다.
05
애플리케이션 쪽 타임아웃과 DB 쪽 대기가 맞물리지 않음
클라이언트가 타임아웃되어 처리를 중단해도 서버 쪽 트랜잭션은 자동으로 끝나지 않습니다. 연결이 끊어질 때까지 남아 있습니다.
確認手順
- 1
열려 있는 트랜잭션을 목록화한다
参照のみ첫 번째 SQL을 실행하여 `open_seconds`가 큰 것부터 확인합니다.
- 2
가장 오래된 트랜잭션을 특정한다
参照のみ로그 해제가 멈춰 있는 경우 가장 오래된 1건이 원인입니다. 두 번째 SQL로 좁힙니다.
- 3
처리 중인지 방치 중인지 구분한다
参照のみ`sys.dm_exec_requests`에 해당 세션의 행이 있는지 확인합니다. 행이 없으면 처리는 끝났고 트랜잭션만 남아 있습니다.
- 4
블로킹 체인을 거슬러 올라간다
参照のみ`blocking_session_id`를 따라가 체인의 시작점이 되는 세션을 특정합니다. 시작점 이외를 멈춰도 해결되지 않습니다.
- 5
접속 원본 애플리케이션을 특정한다
参照のみ`program_name`, `host_name`, `client_net_address`로 어느 애플리케이션·어느 서버에서의 연결인지 확인합니다.
- 6
같은 시간대에 재현되는지 확인한다
参照のみ정기 배치와 같은 시각에 발생하지 않는지 실행 이력과 대조합니다.
対応方法
すぐに実施できる低リスクの対応
원인 애플리케이션 쪽에서 커밋/롤백을 수행시킨다
低애플리케이션의 정상 경로로 트랜잭션을 종료시키는 것이 가장 안전합니다. 운영 담당자와 협력하여 해당 처리를 완료시킵니다.
롤백 중인지 먼저 확인한다
参照のみ`transaction_state = 7`이면 이미 롤백 중입니다. `KILL ... WITH STATUSONLY`로 진행률을 확인하며 완료를 기다립니다. 추가 `KILL`은 의미가 없습니다.
事前検討が必要な変更
애플리케이션 쪽 예외 처리를 수정한다
低try/finally에 상응하는 구조로 커밋 또는 롤백이 반드시 실행되도록 합니다. 재발 방지로서 가장 확실한 대응입니다.
트랜잭션의 범위를 짧게 만든다
低트랜잭션 내부에서 외부 API 호출이나 사용자 입력 대기를 하지 않는 설계로 변경합니다.
장시간 트랜잭션 모니터링을 추가한다
参照のみ`open_seconds`가 임계값을 초과한 세션을 감지하여 알리는 체계를 마련합니다. 감지 임계값은 업무상 최장 배치 시간을 기준으로 정합니다.
SET XACT_ABORT 적용을 검토한다
中실행 시 오류로 트랜잭션이 중간 상태로 남는 경로가 있다면 `SET XACT_ABORT ON` 적용을 검토합니다. 기존 처리의 동작이 바뀌므로 검증 환경에서 확인이 필요합니다.
再起動・サービス影響を伴う変更
세션을 강제 종료한다(KILL)
高미커밋 변경은 롤백됩니다. 롤백에는 원래 처리와 동등하거나 그 이상의 시간이 걸릴 수 있으며, 그동안에도 로그는 해제되지 않습니다. 업무 측 승인을 전제로 한 최종 수단입니다.
분산 트랜잭션의 수동 해결
専門家レビュー必須미해결 분산 트랜잭션은 조정자 쪽 상태 확인이 필요합니다. 데이터베이스 단독 판단으로 강제 해결하면 정합성을 해칠 수 있으므로 전문가의 확인을 전제로 합니다.
!注意事項
- `KILL`은 미커밋 트랜잭션을 롤백합니다. 롤백이 완료될 때까지 로그도 해제되지 않고 테이블 잠금도 유지된 상태입니다. "멈추면 바로 해결된다"고 단정할 수 없습니다.
- `transaction_state = 7`(롤백 중)인 세션에 `KILL`을 반복해도 처리는 빨라지지 않습니다. `WITH STATUSONLY`로 진행률을 확인하며 기다리십시오.
- 블로킹 체인에서는 시작점 세션을 특정하지 않고 말단을 멈춰도 상황이 바뀌지 않습니다. `blocking_session_id`를 반드시 거슬러 올라가십시오.
- 시스템 트랜잭션(`transaction_type = 3`)이나 내부 세션을 대상으로 `KILL`을 실행하지 마십시오.
- `sys.dm_exec_sql_text`가 반환하는 것은 배치 전체의 텍스트입니다. 실행 중인 문을 보려면 `statement_start_offset` / `statement_end_offset`으로 잘라내야 합니다.
バージョン・環境による違い
これで解決しない場合に確認すること
잠금 대기의 세부 내역
`sys.dm_tran_locks`로 어느 리소스에 어떤 모드의 잠금이 걸려 있는지 확인합니다.
애플리케이션의 연결 풀 설정
연결이 풀로 반환될 때 트랜잭션이 재설정되는지, 풀의 최대 수와 대기 시간을 확인합니다.
배치 작업의 실행 이력
`msdb.dbo.sysjobhistory`로 같은 시각에 동작하는 작업이 있는지 확인합니다.
격리 수준 설정
기본값보다 높은 격리 수준을 장시간 유지하고 있지 않은지 애플리케이션 쪽 설정을 확인합니다.
この文書の根拠と限界
製品の公式ドキュメントに基づく説明
SQL Server의 동적 관리 뷰(`sys.dm_tran_active_transactions`, `sys.dm_tran_session_transactions`, `sys.dm_exec_sessions`, `sys.dm_exec_connections`, `sys.dm_exec_requests`), 동적 관리 함수 `sys.dm_exec_sql_text`, 그리고 `DBCC OPENTRAN` / `KILL`의 공개 사양에 기반한 일반적인 절차입니다. 특정 고객의 환경이나 실측값은 포함하지 않습니다.
よくある質問
운영 환경에서 실행할 수 있습니까?
목록화·특정에 사용하는 4개의 SQL(`DBCC OPENTRAN` 포함)은 참조 전용이며 운영 환경에서 실행할 수 있습니다. `KILL`은 미커밋 트랜잭션을 롤백하는 변경 작업이므로 영향 범위 확인과 업무 측 승인을 전제로 하십시오.
AWS RDS에서도 사용할 수 있습니까?
사용할 수 있습니다. 이 글의 DMV는 모두 Amazon RDS for SQL Server에서 참조할 수 있으며, `KILL`도 실행할 수 있습니다. RDS가 사용하는 시스템 세션을 잘못 대상으로 삼지 않도록 `is_user_transaction = 1`로 필터링하십시오.
어떤 권한이 필요합니까?
참조용 SQL에는 VIEW SERVER STATE가 필요합니다. `DBCC OPENTRAN`은 sysadmin 또는 대상 데이터베이스의 db_owner, `KILL`은 ALTER ANY CONNECTION(또는 processadmin / sysadmin)이 필요합니다.
KILL을 해도 끝나지 않는 이유는 무엇입니까?
`KILL`은 롤백을 시작하는 명령이며, 완료까지 걸리는 시간은 원래 트랜잭션이 변경한 데이터량에 의존합니다. `transaction_state = 7`은 롤백 진행 중임을 나타내며, 이 상태에서는 기다리는 것이 유일한 대응입니다.
결과를 어떻게 판단합니까?
`open_seconds`가 업무상 최장 처리 시간을 명확히 초과하고, `sys.dm_exec_requests`에 해당 세션의 행이 없다면 "처리는 끝났는데 트랜잭션만 남아 있는" 상태입니다. 이것이 대응 대상이 됩니다.
この文書がカバーする質問
- BEGIN TRAN 방치 세션 감지
- SQL Server에서 미커밋 트랜잭션을 찾고 싶다
- 로그가 해제되지 않는 원인 트랜잭션을 특정하고 싶다
- 블로킹의 시작점 세션을 찾고 싶다
リスク表示の意味
- 参照のみデータと設定を変更しません。
- 低影響は限定的ですが、権限と負荷の確認が必要です。
- 中性能・ロック・コストに影響する可能性があります。
- 高障害・データ損失・復旧作業が発生する可能性があります。
- 専門家レビュー必須本番適用前に別途レビューが必須です。
GIIPの対応範囲
방치된 트랜잭션은 발생한 순간에는 누구도 알아채지 못하고, 로그 고갈이나 블로킹으로 표면화되었을 때는 이미 업무가 멈춰 있는 성질을 가집니다. GIIP에서는 여러 데이터베이스에 대해 트랜잭션의 열린 시간을 정기적으로 가져오고, 임계값을 초과한 시점에 AI 에이전트가 해당 세션과 접속 원본 애플리케이션까지 특정한 후 담당자에게 통지합니다. `KILL`처럼 영향이 큰 작업은 자동 실행하지 않고, 판단과 승인은 사람이 하는 방식으로 구분하고 있습니다.
執筆・技術検証
GIIP プロダクション運用チーム
大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。
RDS for SQL Server에서 트랜잭션 로그 사용률을 확인하는 방법
로그 사용률을 DBCC SQLPERF(LOGSPACE)와 sys.dm_db_log_space_usage로 확인하고, 해제되지 않는 이유를 log_reuse_wait_desc로 구분하는 참조 전용 절차입니다.
sql-serverSQL Server에서 CXPACKET 대기가 많을 때의 원인과 확인 방법
sys.dm_os_wait_stats와 sys.dm_os_waiting_tasks로 CXPACKET을 평가하고, CXCONSUMER와의 구분을 바탕으로 병렬 처리 수준 재검토로 나아가기 위한 절차입니다.
sql-serverSQL Server에서 테이블별 통계 정보 업데이트 일시를 확인하는 SQL
sys.stats와 STATS_DATE로 테이블·통계별 최종 업데이트 일시와 업데이트 이후 변경된 행 수를 목록화하는 참조 전용 SQL입니다.
monitoring서버와 데이터베이스를 24시간 모니터링할 때 설정할 항목
24시간 모니터링을 설계할 때의 모니터링 대상·임계값 사고방식·에스컬레이션 체계·외부 모니터링의 필요성을 계층별로 정리한 체크리스트입니다.
関連サービス
장시간 트랜잭션 모니터링을 설계하기
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
장시간 트랜잭션 모니터링을 설계하기