안녕하세요.
오늘은 PL/SQL과 내장 함수 및 SQL 속도에 대하여 알아보겠습니다.
PL/SQL이 네이티브 코드로 완전히 컴파일된 내장 함수에 비해 상대적으로 느리게 동작하는데요.
PL/SQL은 Java와 비슷하게 인터프리터(interpreter) 언어로 동작하는 측면이 있습니다.
PL/SQL 코드는 데이터베이스 내에서 실행되며, SQL 엔진과 PL/SQL 엔진 간의 상호작용이 필요합니다.
이 때문에 PL/SQL은 데이터베이스의 native 코드로 완전히 컴파일된 함수나 프로시저에 비해 상대적으로 느릴 수 있습니다.
[ 1 ]
물론 Java와 비슷한거지 Java 인터프리터 언어와 완전히 동일하다고 할 수는 없습니다.
- PL/SQL 컴파일 방식
PL/SQL 코드는 데이터베이스에 저장되면서 바이트코드로 컴파일됩니다. 실행 시 PL/SQL 엔진이 바이트코드를 해석하거나 최적화된 네이티브 코드로 변환하여 실행합니다. - 최적화된 엔진
Oracle Database는 PL/SQL 엔진과 SQL 엔진 간의 통합 작업을 최적화하여 성능 저하를 줄입니다. 특히, 네트워크 트래픽이 필요 없기 때문에 클라이언트-서버 모델에서 발생할 수 있는 오버헤드가 없습니다. - 네이티브 컴파일
Oracle은 PL/SQL 코드를 네이티브 코드(C 코드)로 컴파일할 수 있는 기능을 제공합니다. 이렇게 하면 성능이 크게 개선됩니다. (다만, 이 방식은 설정 및 운영에 추가적인 복잡성이 있습니다.)
정리
PL/SQL은 기본적으로 인터프리터 방식으로 실행되므로 네이티브 코드로 완전히 컴파일된 함수보다는 느릴 수 있습니다. 그러나 데이터베이스 내에서 실행되므로 네트워크 오버헤드가 없고, 최적화된 엔진 덕분에 많은 경우 Java 같은 일반적인 인터프리터 언어보다는 효율적으로 작동합니다.
** 심화 단계 **
[2]
PL/SQL이 네이티브 코드로 완전히 컴파일된 내장 함수에 비해 상대적으로 느리게 동작하는것에 대하여 좀더 깊게 알아보겠습니다.
PL/SQL은 네이티브 코드로 작성된 내장 함수보다 느릴 수 있는데, 이는 컨텍스트 스위칭, 인터프리터 방식 실행, 재귀 호출의 부하 등 여러 이유에서 기인합니다. 재귀 호출이 성능에 미치는 영향을 포함해 살펴보겠습니다.
1. 컨텍스트 스위칭(Context Switching)
PL/SQL과 SQL 엔진 간 상호작용에서 발생하는 컨텍스트 스위칭은 PL/SQL의 주요 성능 저하 요인 중 하나입니다.
작동 방식
- PL/SQL 블록에서 SQL 문이 실행되면, PL/SQL 엔진이 SQL 엔진으로 제어를 넘겨야 합니다.
- SQL 엔진이 작업을 수행한 뒤 결과를 PL/SQL로 반환하면, 다시 PL/SQL 컨텍스트로 전환해야 합니다.
컨텍스트 스위칭 비용
- CPU 오버헤드: 각 전환 시 상태 저장 및 복구.
- 데이터 이동 비용: SQL과 PL/SQL 간 데이터 교환.
예시 -
다음 PL/SQL 코드는 SQL 문이 반복적으로 호출되며 매번 컨텍스트 스위칭이 발생합니다.
DECLARE
total_sales NUMBER;
BEGIN
FOR i IN 1..1000 LOOP
SELECT SUM(sales) INTO total_sales FROM sales_table WHERE id = i;
END LOOP;
END;
이 경우 1,000번의 컨텍스트 전환이 발생하므로 실행 속도가 크게 저하될 수 있습니다.
개선 방안 -
- 가능하다면 단일 SQL 문으로 작업을 병합.
SELECT id, SUM(sales)
INTO total_sales
FROM sales_table
GROUP BY id;
2. 인터프리터 방식 실행
PL/SQL은 기본적으로 바이트코드로 변환된 후 실행됩니다.
이 방식은 네이티브 코드와 비교해 다음과 같은 성능 저하를 유발합니다.
- 명령 해석 시간: 바이트코드가 실행될 때마다 PL/SQL 엔진이 이를 해석해야 함.
- 추가적인 런타임 오버헤드: 실행 중 추가적인 관리 작업이 필요.
네이티브 코드는 CPU에서 바로 실행되는 반면, PL/SQL은 이 중간 과정이 필요하기 때문에 느릴 수 있습니다.
개선 방안 -
- PL/SQL 코드를 네이티브 코드로 컴파일하는 기능을 활용(Oracle Database의 NATIVE 옵션).
3. 재귀 호출(Recursive Call)의 부하
재귀 호출이란?
재귀 호출은 함수가 자신을 호출하는 방식으로, 문제를 반복적으로 작은 부분으로 나누는 데 유용합니다.
하지만 반복적으로 호출되는 동안 스택 메모리 사용과 함수 호출 오버헤드가 누적되어 성능에 부정적인 영향을 줄 수 있습니다.
PL/SQL에서의 예시
재귀 호출을 사용한 팩토리얼 계산 방식 -
CREATE OR REPLACE FUNCTION factorial(n NUMBER) RETURN NUMBER IS
BEGIN
IF n = 0 THEN
RETURN 1;
ELSE
RETURN n * factorial(n - 1);
END IF;
END;
/
위 함수는 호출될 때마다 함수 스택이 쌓입니다. factorial(5)를 계산하면 함수는 총 5번 호출되며,
각 호출 시 스택 메모리와 함수 호출 오버헤드가 발생합니다.
재귀 호출의 성능 부하
- 스택 메모리 소모: 함수 호출 시마다 스택에 상태를 저장. 깊은 재귀 호출은 메모리 부족을 유발할 수 있음.
- 함수 호출 오버헤드: 호출 시마다 변수 초기화, 상태 저장 및 복구 등 추가 작업 발생.
개선 방안 -
재귀 호출은 반복문으로 대체해 성능을 최적화할 수 있습니다.
CREATE OR REPLACE FUNCTION factorial_iterative(n NUMBER) RETURN NUMBER IS
result NUMBER := 1;
BEGIN
FOR i IN 1..n LOOP
result := result * i;
END LOOP;
RETURN result;
END;
/
위 반복문 기반 팩토리얼 계산은 재귀 호출에 비해 메모리 사용량과 함수 호출 오버헤드가 적습니다.
4. 내장 함수와 PL/SQL의 비교
Oracle 내장 함수는 데이터베이스 엔진에 최적화된 네이티브 코드로 작성되며 다음과 같은 이점이 있습니다:
- 컨텍스트 스위칭 없음: 내장 함수는 SQL 엔진 내에서 실행되므로 PL/SQL과 SQL 간 전환이 필요 없음.
- 네이티브 코드 실행: 명령어가 CPU에서 직접 실행됨.
- 고도로 최적화된 알고리즘: Oracle 개발자가 데이터 구조와 알고리즘을 최적화.
예시 비교 -
PL/SQL로 작성한 문자열 연결과 Oracle 내장 함수 사용 비교.
-- PL/SQL 방식 (느림)
DECLARE
result VARCHAR2(4000) := '';
BEGIN
FOR i IN 1..1000 LOOP
result := result || 'Hello';
END LOOP;
END;
-- Oracle 내장 함수 방식 (빠름)
SELECT RPAD('Hello', 5000, 'Hello') INTO result FROM dual;
내장 함수는 PL/SQL보다 훨씬 빠르게 실행됩니다.
요약
PL/SQL이 내장 함수보다 느린 이유는 다음과 같습니다.
- 컨텍스트 스위칭: PL/SQL과 SQL 엔진 간의 전환 비용.
- 인터프리터 방식 실행: 네이티브 코드에 비해 실행 시간이 더 필요.
- 재귀 호출의 부하: 스택 메모리 사용과 함수 호출 오버헤드.
- 런타임 환경: 네이티브 함수는 PL/SQL보다 더 최적화된 데이터 처리 환경을 가짐.
개선 방안 -
- 단일 SQL 문으로 작업 병합.
- 반복문 사용으로 재귀 호출 대체.
- PL/SQL 코드를 네이티브 코드로 컴파일.
- PL/SQL의 집합 연산(FORALL, BULK COLLECT) 활용.
이런 방법을 통해 PL/SQL의 성능 저하 문제를 완화할 수 있습니다.
감사합니다.
'Database' 카테고리의 다른 글
[ Oracle ] "SQL의 튜닝 == 힌트 사용" 일까? (0) | 2025.01.09 |
---|---|
[ Oracle ] Nested Loop Join,Sort-Merge Join,Hash Join의 비교 (0) | 2025.01.08 |
[ Oracle ] 인덱스 클러스터 테이블과 해시 클러스터 테이블 (0) | 2024.12.30 |
[ Oracle ] index에 대하여.. (2) | 2024.12.27 |
[ SQL ] Hint에 대하여 알아보자 (feat.Oracle) (1) | 2024.12.23 |