728x90
반응형

커서 (cursor)를 사용하는 이유
SQL은 기본적으로 집합 (set)기반 언어이며 다음 같은 경우 레코드 하나하나를 반복해서 처리할 필요가 있다.
- 레코드 단위로 복잡한 로직 처리
- 예: 조건에 따라 다른 테이블에 INSERT/UPDATE
- 예: 이전 행 값을 참조해서 현재 행 처리
- 동적 SQL, 또는 조건 분기 로직 필요
- SELECT 결과에 따라 프로시저 실행, 로그 기록 등
- 다양한 테이블 또는 조건에 따라 서로 다른 작업 수행
- 다중 트랜잭션 처리 필요
- 레코드마다 커밋 또는 롤백이 필요한 경우
| 항목 | WHILE + 임시 테이블 | CURSOR |
| 처리 단위 | 집합 기반 or 인덱스 기반 루프 | 행(row) 기반 반복 |
| 코드 복잡도 | 비교적 단순 | 선언, OPEN, FETCH, CLOSE 필요 |
| 성능 | 보통 더 빠름 | 상대적으로 느림 |
| 유연성 | 제한적 | 매우 유연 (방향 이동, 커서 유형, 동시성 제어 등) |
| 대표 예 | 단순 루프, 숫자 증가, 인덱스 기반 반복 | 행마다 조건 분기, 복잡한 로직 필요 시 |
다음과 같은 단점이 존재한다.
- 성능 저하 반복 처리이므로 집합 기반보다 훨씬 느림 (특히 대용량 시)
- 자원 소모 서버 리소스(메모리, CPU)를 더 많이 사용함
- 복잡한 코드 구조 선언/OPEN/FETCH/조건/종료 코드 등 구조가 길어짐
- 병목 발생 가능 트랜잭션 안에서 커서를 오래 사용 시 동시성 저하 가능
커서 대신 사용할 수 있는 대안들
- WHILE + ROW_NUMBER() or IDENTITY 인덱스 기반 반복 처리
- MERGE, UPDATE ... FROM, CASE 등 조건 분기 포함한 집합 처리
- 사용자 정의 함수 또는 프로시저 집합 기반 처리로 성능 개선 가능
- 임시 테이블 or 테이블 변수 + 루프 커서 대신 데이터 저장 후 인덱스 접근
1. 커서 선언 기본 형식
DECLARE cursor_name CURSOR
[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
FOR
SELECT ...
2. 커서 범위 옵션
- LOCAL- 현재 배치(batch) 또는 프로시저 내에서만 사용 가능 (기본값은 DB 설정에 따라 다름)
- GLOBAL - 커서가 연결된 세션 전체에서 사용 가능
3. 스크롤 방향 옵션
- FORWARD_ONLY - 순방향으로만 이동 가능 (가장 빠름, 기본 옵션 중 하나)
- SCROLL - NEXT, PRIOR, FIRST, LAST, ABSOLUTE, RELATIVE 등 임의의 방향으로 이동 가능
4. 커서 유형 옵션 (데이터 스냅샷 방식)
- STATIC - 쿼리 결과를 임시 테이블에 저장. 결과가 고정되어 커서 이동이 빠름. 데이터 변경 반영 안 됨.
- KEYSET - 결과 집합의 키만 고정. 값은 실시간 반영됨. 삽입된 행은 보이지 않음. 삭제된 행은 감지됨.
- DYNAMIC - 완전히 동적. 삽입/수정/삭제 모두 실시간 반영됨. 성능은 가장 느릴 수 있음.
- FAST_FORWARD - FORWARD_ONLY + READ_ONLY 조합으로 가장 빠름. 데이터 수정 불가, 커서 이동은 순방향만 가능.
5. 동시성 옵션 (잠금/변경 감지 방식)
- READ_ONLY 읽기 전용. 데이터 변경 시도 시 에러 발생. 가장 가볍고 빠름
- SCROLL_LOCKS 커서가 포인트한 행을 잠금(Lock) 처리. 데이터 일관성 유지
- OPTIMISTIC 잠금 없이 사용자가 데이터를 변경할 때 변경 여부를 체크해서 업데이트 시 충돌 여부 판단 (낙관적 동시성 제어)
6. FETCH 이동 방향 키워드
FETCH [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n ] FROM cursor_name;
- NEXT 다음 행 (기본)
- PRIOR 이전 행
- FIRST 첫 행
- LAST 마지막 행
- ABSOLUTE n 특정 행 번호로 이동 (1부터 시작)
- RELATIVE n 현재 위치에서 n만큼 이동 (양수는 앞으로, 음수는 뒤로)
scroll 옵션이 없으면 위 옵션 중에서 NEXT만 사용 가능.
7. ISO 관련 – 트랜잭션 격리 수준과 커서
커서 자체는 ISO 트랜잭션 격리 수준을 설정하지 않지만, 커서 내에서 실행되는 SELECT 문은 세션의 격리 수준의 영향을 받는다.
SET TRANSACTION ISOLATION LEVEL
READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SNAPSHOT | SERIALIZABLE;
8. CLOSE, DEALLOCATE
- CLOSE cursor_name; – 커서를 닫지만 메모리는 유지
- DEALLOCATE cursor_name; – 커서를 메모리에서 제거 (종료 후 항상 해주는 것이 좋음)
- 예시
DECLARE my_cursor CURSOR LOCAL STATIC READ_ONLY FOR
SELECT name FROM sys.objects;
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO @name;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @name;
FETCH NEXT FROM my_cursor INTO @name;
END
CLOSE my_cursor;
DEALLOCATE my_cursor;'프로그래밍&IT > MySQL, Oracle, SQL Server' 카테고리의 다른 글
| MS Sql Server - Stored Procedures (스토어드 프로시저) (4) | 2025.07.30 |
|---|---|
| MS Sql Server - User Defined Functions (UDF) (0) | 2025.07.29 |
| MS Sql Server - 인덱스 (5) | 2025.07.27 |
| [Oracle] 인덱스 종류 그리고 인덱스를 이용하는 & 이용못하는 쿼리 (1) | 2024.10.30 |
| [Oracle] View에 대해서 알아보자 (1) | 2024.10.30 |