DATABASE/MsSQL

데이터베이스 커서(cursor) 그리고 지양해야하는 이유

Fehoon- 2023. 7. 8. 10:22

커서(cursor)란?

  • 데이터베이스에서 한 번에 한 행씩 처리하는 데 사용되는 기능입니다. 일반적으로 커서는 단일 행이나 다중 행 데이터에 접근하고 처리해야 할 때 유용합니다.
  • 커서는 선언, 열기, 데이터읽기, 닫기, 할당해제 등의 단계로 나뉜다.

1. 선언(DECLARE):

  • 커서를 선언하기 위해 DECLARE CURSOR 문을 사용합니다. 이 단계에서는 커서의 이름, 커서 속성 및 커서와 연관된 SELECT 문을 정의합니다. 커서에 필요한 컬럼들을 선택하고, WHERE 절과 JOIN 절을 사용하여 데이터를 필터링하거나 조인할 수 있습니다.
DECLARE cur CURSOR FOR
SELECT Column1, Column2
FROM Table
WHERE Condition;

2. 열기(OPEN):

  • OPEN 문을 사용하여 선언된 커서를 엽니다. 커서를 열면 커서가 데이터를 읽을 준비가 되고, 첫 번째 행을 가리키게 됩니다.
OPEN cur;

3. 데이터읽기(FETCH):

  • FETCH 문을 사용하여 커서에서 한 번에 한 행씩 데이터를 읽습니다. FETCH NEXT 문은 다음 행을 가져오고, FETCH PRIOR 문은 이전 행을 가져옵니다. 읽은 데이터는 커서의 변수에 할당됩니다.
  • 이 단계는 반복문과 함께 사용하여 커서를 통해 데이터를 순차적으로 처리하는 데 사용됩니다.
FETCH NEXT FROM cur INTO @var1 @var2 ...

4. 닫기(CLOSE):

  • CLOSE 문을 사용하여 커서를 닫습니다. 커서가 닫히면 더 이상 데이터를 읽을 수 없습니다. 단순히 커서를 닫기 위해서만 사용되는 것이며, 메모리나 자원은 아직 할당 상태입니다.
CLOSE cur;

5. 할당 해제(Deallocate):

  • DEALLOCATE 문을 사용하여 커서와 관련된 메모리 및 자원을 할당 해제합니다. 커서를 더 이상 사용하지 않을 때 호출되며, 메모리와 자원을 반환합니다.
DELLOCATE cur;

- 예시

  • 주문 날짜(OrderDate) 범위를 입력받아 해당 기간 동안의 주문 상품 수량을 계산하는 커서를 사용하는 예.
Order 테이블:

OrderID (주문 ID)
CustomerID (고객 ID)
OrderDate (주문 날짜)
OrderItem 테이블:

OrderItemID (주문 상품 ID)
OrderID (주문 ID)
ProductID (상품 ID)
Quantity (수량)
DECLARE @startDate DATE, @endDate DATE, @totalQuantity INT
SET @startDate = '2023-01-01'
SET @endDate = '2023-03-31'
SET @totalQuantity = 0

DECLARE @itemQuantity INT

DECLARE cur CURSOR FOR
SELECT oi.Quantity
FROM OrderItem oi
INNER JOIN [Order] o ON oi.OrderID = o.OrderID
WHERE o.OrderDate BETWEEN @startDate AND @endDate

OPEN cur
FETCH NEXT FROM cur INTO @itemQuantity

WHILE @@FETCH_STATUS = 0
BEGIN
  SET @totalQuantity = @totalQuantity + @itemQuantity

  FETCH NEXT FROM cur INTO @itemQuantity
END

CLOSE cur
DEALLOCATE cur

PRINT '총 수량: ' + CAST(@totalQuantity AS VARCHAR)

- 업데이트 커서 예시

DECLARE @id INT, @newSalary DECIMAL(10, 2)
DECLARE cur CURSOR FOR
SELECT Id, Salary FROM Employees WHERE Department = 'Finance'

OPEN cur
FETCH NEXT FROM cur INTO @id, @newSalary

WHILE @@FETCH_STATUS = 0
BEGIN
  -- 행 업데이트
  UPDATE Employees SET Salary = @newSalary * 1.1 WHERE Id = @id

  FETCH NEXT FROM cur INTO @id, @newSalary
END

CLOSE cur
DEALLOCATE cur

- 커서(cursor)와 함수(function)은 지양해야 한다.

  • 커서나 함수를 사용해보면 알겠지만 처리속도가 매우 느린편이다.

  • 일반적으로 SQL Server에서는 커서(cursor)와 함수(function)의 사용을 가능한 한 지양하는 것이 좋습니다. 이는 성능 및 유지보수 관점에서 권장되는 접근 방법입니다. 그러나 상황에 따라서는 커서와 함수를 사용해야 할 수도 있습니다.

  • 커서는 데이터베이스에서 데이터를 한 번에 한 행씩 처리하는 데 사용됩니다. 커서를 사용하면 반복적인 작업을 수행할 수는 있지만, 대량의 데이터에 대해 처리할 경우 성능 문제가 발생할 수 있습니다. 커서는 행 단위로 작업하기 때문에 대량의 데이터를 처리하는 경우에는 집합 기반(set-based) 작업에 비해 더 많은 시간과 자원을 요구할 수 있습니다. 따라서 커서 대신 집합 기반의 SQL 구문을 사용하는 것이 일반적으로 성능상 유리합니다.

  • 함수는 코드의 재사용성과 모듈화를 위해 사용됩니다. 하지만 SQL Server에서 사용자 정의 함수(user-defined function)를 사용할 경우 성능 문제가 발생할 수 있습니다. 함수는 행 단위로 작업하며, 함수를 사용하는 쿼리는 함수의 호출 횟수에 따라 성능이 저하될 수 있습니다. 함수를 사용하는 쿼리는 실행 계획을 최적화하기 어렵기 때문에 성능 문제가 발생할 수 있습니다. 대신에 인라인 테이블 함수(inline table-valued function)나 조인 등을 사용하여 집합 기반의 SQL 구문으로 작성하는 것이 성능상 유리합니다.
반응형