2026년 05월 23일 | Oracle DBA 가이드
?? 이 글에서 다루는 내용
ORA-00069 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-00069란?
ORA-00069 에러는 “cannot acquire lock – table locks disabled”, 즉 테이블 잠금(Table Lock, 일명 TM Lock)이 비활성화된 상태에서 해당 테이블에 잠금을 획득하려 할 때 발생하는 에러입니다. Oracle은 DML(INSERT, UPDATE, DELETE) 및 DDL 작업 시 테이블 수준의 잠금을 사용하는데, 특정 테이블에 대해 DISABLE TABLE LOCK 옵션이 설정되어 있으면 이 잠금 획득 자체가 불가능해집니다. 주로 고가용성 환경이나 Oracle Parallel Server(OPS) / RAC 환경에서 성능 최적화를 위해 의도적으로 테이블 잠금을 비활성화한 경우, 또는 실수로 비활성화된 경우에 이 에러가 발생합니다.
주요 발생 원인
1. 의도적 또는 실수로 인한 DISABLE TABLE LOCK 설정
가장 흔한 원인으로, DBA 또는 개발자가 ALTER TABLE ... DISABLE TABLE LOCK 명령을 실행하여 해당 테이블의 TM 잠금을 비활성화한 경우입니다. RAC 환경에서 인터커넥트 트래픽을 줄이기 위한 성능 튜닝 목적으로 이 설정을 적용하기도 하지만, 이후 일반 DML 작업 시 ORA-00069가 발생하게 됩니다. 운영 중 다른 DBA나 스크립트에 의해 실수로 적용된 경우도 많아, 장애 발생 시 반드시 이 설정 여부를 우선 확인해야 합니다.
2. DDL 작업(ALTER TABLE, TRUNCATE 등) 수행 시 잠금 충돌
TRUNCATE TABLE, ALTER TABLE ... ADD COLUMN 등 DDL 작업은 내부적으로 테이블 수준의 배타적 잠금(Exclusive TM Lock)을 요구합니다. 테이블 잠금이 비활성화된 상태에서 이러한 DDL을 실행하면 ORA-00069가 발생합니다. 특히 배치 작업 스크립트나 마이그레이션 스크립트에서 TRUNCATE 후 INSERT 패턴을 사용할 때 빈번히 마주치는 상황입니다.
3. Oracle Parallel Server(OPS) 또는 RAC 환경의 잘못된 구성
Oracle RAC(Real Application Clusters) 환경에서는 노드 간 글로벌 잠금 관리(Global Enqueue Service, GES)를 통해 테이블 잠금을 처리합니다. 일부 오래된 RAC 설정 가이드에서는 성능을 위해 특정 테이블의 잠금을 비활성화하도록 권고한 경우가 있으며, 이러한 설정이 남아있는 상태에서 신규 애플리케이션이 해당 테이블에 접근하면 에러가 발생합니다. 인프라 이전이나 RAC 노드 증설 후 기존 설정이 그대로 유지되어 문제가 불거지는 경우도 실무에서 자주 확인됩니다.
해결 방법
원인 1 해결: 테이블 잠금 비활성화 여부 확인 및 재활성화
먼저 현재 테이블의 잠금 상태를 확인합니다. DBA_TABLES 또는 USER_TABLES 뷰의 ROW_MOVEMENT 컬럼과 함께 TABLE_LOCK 관련 정보를 조회할 수 있습니다.
-- 테이블 잠금 상태 확인 (DBA 권한 필요)
SELECT owner,
table_name,
row_movement,
-- TABLE_LOCK 비활성화 여부는 직접 컬럼이 없으므로 아래 방법으로 확인
status
FROM dba_tables
WHERE table_name = 'YOUR_TABLE_NAME'
AND owner = 'YOUR_SCHEMA';
-- v$locked_object와 함께 현재 잠금 현황 확인
SELECT lo.oracle_username,
lo.os_user_name,
lo.session_id,
lo.locked_mode,
do.object_name,
do.object_type
FROM v$locked_object lo
JOIN dba_objects do ON lo.object_id = do.object_id
WHERE do.object_name = 'YOUR_TABLE_NAME';
테이블 잠금 비활성화 여부를 확인하는 가장 확실한 방법은 실제로 잠금을 시도해 보거나, DBMS_METADATA로 DDL을 추출하는 것입니다.
-- 테이블 DDL 추출을 통해 DISABLE TABLE LOCK 여부 확인
SELECT dbms_metadata.get_ddl('TABLE', 'YOUR_TABLE_NAME', 'YOUR_SCHEMA')
FROM dual;
테이블 잠금이 비활성화되어 있음을 확인했다면, 아래 명령으로 즉시 재활성화합니다.
-- 테이블 잠금 재활성화 (핵심 해결 명령)
ALTER TABLE your_schema.your_table_name ENABLE TABLE LOCK;
-- 재활성화 후 정상 DML 작업 가능 여부 테스트
LOCK TABLE your_schema.your_table_name IN ROW SHARE MODE;
-- 정상이라면 에러 없이 잠금 획득됨
COMMIT;
원인 2 해결: DDL 수행 전 잠금 상태 확인 절차 추가
배치 스크립트나 마이그레이션 스크립트에서 TRUNCATE 전에 잠금 상태를 확인하고, 비활성화된 경우 자동으로 활성화하는 로직을 추가합니다.
-- 잠금 비활성화 상태에서 TRUNCATE 시도 시 ORA-00069 발생 예시
-- (아래는 에러 재현 및 해결 흐름)
-- Step 1: 테이블 잠금 비활성화 (문제 상황 재현)
ALTER TABLE hr.employees DISABLE TABLE LOCK;
-- Step 2: 이 상태에서 TRUNCATE 시도 → ORA-00069 발생
-- TRUNCATE TABLE hr.employees; ← 에러 발생!
-- Step 3: 잠금 재활성화 후 TRUNCATE 정상 수행
ALTER TABLE hr.employees ENABLE TABLE LOCK;
TRUNCATE TABLE hr.employees;
-- 배치 프로시저에서 활용 가능한 안전한 패턴
CREATE OR REPLACE PROCEDURE safe_truncate(
p_owner IN VARCHAR2,
p_table_name IN VARCHAR2
) AS
v_sql VARCHAR2(500);
BEGIN
-- 1. 테이블 잠금 활성화 보장
v_sql := 'ALTER TABLE ' || p_owner || '.' || p_table_name || ' ENABLE TABLE LOCK';
EXECUTE IMMEDIATE v_sql;
-- 2. 안전하게 TRUNCATE 수행
v_sql := 'TRUNCATE TABLE ' || p_owner || '.' || p_table_name;
EXECUTE IMMEDIATE v_sql;
DBMS_OUTPUT.PUT_LINE(p_owner || '.' || p_table_name || ' truncated successfully.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RAISE;
END safe_truncate;
/
-- 프로시저 실행
EXEC safe_truncate('HR', 'EMPLOYEES');
원인 3 해결: RAC 환경에서 잘못 비활성화된 테이블 일괄 점검 및 복구
RAC 환경에서 여러 테이블에 걸쳐 잠금이 비활성화된 경우, 아래 스크립트로 일괄 확인 및 활성화 스크립트를 생성합니다.
-- DISABLE TABLE LOCK 상태인 테이블 목록 및 활성화 스크립트 생성
-- (실제로 TABLE LOCK 비활성화는 딕셔너리에 특정 플래그로 저장됨)
-- 아래는 테스트 환경에서 검증된 확인 방법
-- sys.obj$ 기반 플래그 확인 (고급 방법, SYS 권한 필요)
SELECT o.name AS table_name,
u.name AS owner,
o.flags,
-- flags 비트 32 = TABLE LOCK DISABLED
CASE WHEN BITAND(o.flags, 32) = 32
THEN 'TABLE LOCK DISABLED'
ELSE 'TABLE LOCK ENABLED'
END AS lock_status,
-- 활성화 스크립트 자동 생성
CASE WHEN BITAND(o.flags, 32) = 32
THEN 'ALTER TABLE ' || u.name || '.' || o.name || ' ENABLE TABLE LOCK;'
ELSE NULL
END AS fix_script
FROM sys.obj$ o
JOIN sys.user$ u ON o.owner# = u.user#
WHERE o.type# = 2 -- TABLE
AND BITAND(o.flags, 32) = 32 -- TABLE LOCK DISABLED 조건
ORDER BY u.name, o.name;
-- 생성된 스크립트를 실행하여 일괄 복구
-- 위 쿼리 결과의 fix_script 컬럼 값을 복사하여 실행하거나,
-- 아래와 같이 동적으로 처리 가능
BEGIN
FOR rec IN (
SELECT 'ALTER TABLE ' || u.name || '.' || o.name || ' ENABLE TABLE LOCK' AS fix_sql
FROM sys.obj$ o
JOIN sys.user$ u ON o.owner# = u.user#
WHERE o.type# = 2
AND BITAND(o.flags, 32) = 32
AND u.name NOT IN ('SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN') -- 시스템 스키마 제외
) LOOP
DBMS_OUTPUT.PUT_LINE('Executing: ' || rec.fix_sql);
EXECUTE IMMEDIATE rec.fix_sql;
END LOOP;
DBMS_OUTPUT.PUT_LINE('All table locks re-enabled successfully.');
END;
/
예방 방법
1. 테이블 잠금 변경 작업에 대한 권한 통제 및 변경 관리 프로세스 수립
ALTER TABLE ... DISABLE TABLE LOCK 명령은 운영 환경에서 매우 신중하게 사용해야 하며, 가급적 DBA 전용 권한으로 제한해야 합니다. DDL 변경 이력을 추적하기 위해 DDL 트리거를 활용하여 테이블 잠금 변경 이벤트를 로깅하는 체계를 갖추면 장애 발생 시 원인 추적이 훨씬 수월해집니다.
-- DDL 변경 감사를 위한 로그 테이블 및 트리거 구성
CREATE TABLE dba_ddl_audit_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY,
event_date TIMESTAMP DEFAULT SYSTIMESTAMP,
db_user VARCHAR2(100),
os_user VARCHAR2(100),
machine VARCHAR2(100),
object_type VARCHAR2(50),
object_name VARCHAR2(128),
ddl_text CLOB,
CONSTRAINT pk_ddl_audit PRIMARY KEY (log_id)
);
-- DDL 이벤트 트리거 (시스템 레벨 또는 스키마 레벨)
CREATE OR REPLACE TRIGGER trg_ddl_audit
AFTER DDL ON DATABASE
BEGIN
-- TABLE LOCK 관련 ALTER TABLE 감지
IF ora_dict_obj_type = 'TABLE' THEN
INSERT INTO dba_ddl_audit_log (
db_user, os_user, machine, object_type, object_name
)
SELECT
sys_context('USERENV', 'SESSION_USER'),
sys_context('USERENV', 'OS_USER'),
sys_context('USERENV', 'HOST'),
ora_dict_obj_type,
ora_dict_obj_name
FROM dual;
COMMIT;
END IF;
END;
/
2. 정기적인 테이블 잠금 상태 점검 스크립트를 모니터링 체계에 편입
운영 환경에서 주기적(일별 또는 주별)으로 테이블 잠금 비활성화 여부를 점검하는 쿼리를 스케줄링하여, 비정상 상태가 감지되면 즉시 DBA에게 알림이 오도록 구성합니다. Oracle Enterprise Manager(OEM)의 커스텀 메트릭 기능이나 외부 모니터링 도구(Zabbix, Grafana 등)와 연동하면 효과적입니다.
주요 ORA 에러를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
? 본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.