반응형
오라클 함수(Function)는 특정 값을 반환하는 PL/SQL 서브프로그램으로, SQL 쿼리 내에서 직접 호출할 수 있다는 점에서 프로시저와 차별화됩니다. 이 가이드에서는 함수의 조회, 관리, 최적화까지 실무에서 필요한 모든 내용을 다룹니다.
목차
- 함수 기본 정보 조회
- 함수 파라미터 및 반환값 조회
- 함수 소스 코드 조회
- 함수 성능 분석
- DETERMINISTIC 함수 관리
- 함수 의존성 및 영향도 분석
- 함수 작성 Best Practices
- 함수 vs 프로시저 선택 가이드
1. 함수 기본 정보 조회
함수 존재 여부 및 상태 확인
SELECT
OBJECT_NAME,
OBJECT_TYPE,
STATUS,
CREATED,
LAST_DDL_TIME
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
AND OBJECT_NAME = UPPER('함수명');
주요 컬럼:
STATUS: VALID(정상) / INVALID(오류)CREATED: 최초 생성일LAST_DDL_TIME: 마지막 변경일
전체 함수 목록 조회
SELECT
OBJECT_NAME AS "함수명",
STATUS AS "상태",
TO_CHAR(CREATED, 'YYYY-MM-DD') AS "생성일",
TO_CHAR(LAST_DDL_TIME, 'YYYY-MM-DD HH24:MI:SS') AS "최종수정일"
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
ORDER BY OBJECT_NAME;
스키마별 함수 통계
SELECT
OWNER AS "스키마",
COUNT(*) AS "함수개수",
SUM(CASE WHEN STATUS = 'VALID' THEN 1 ELSE 0 END) AS "정상",
SUM(CASE WHEN STATUS = 'INVALID' THEN 1 ELSE 0 END) AS "오류"
FROM ALL_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
GROUP BY OWNER
ORDER BY COUNT(*) DESC;
2. 함수 파라미터 및 반환값 조회
함수 시그니처 확인
SELECT
ARGUMENT_NAME,
POSITION,
DATA_TYPE,
IN_OUT,
DATA_LENGTH,
DATA_PRECISION,
DATA_SCALE,
DEFAULT_VALUE
FROM ALL_ARGUMENTS
WHERE OBJECT_NAME = UPPER('함수명')
AND PACKAGE_NAME IS NULL -- 패키지 함수 제외
ORDER BY POSITION;
반환값 식별:
POSITION = 0: 함수의 반환값ARGUMENT_NAME IS NULL: 반환값 (일부 케이스)
패키지 내 함수 파라미터 조회
SELECT
OBJECT_NAME AS "패키지명",
SUBPROGRAM_ID AS "서브프로그램ID",
ARGUMENT_NAME AS "파라미터명",
POSITION,
DATA_TYPE,
IN_OUT
FROM ALL_ARGUMENTS
WHERE PACKAGE_NAME = UPPER('패키지명')
AND OBJECT_NAME = UPPER('함수명')
ORDER BY POSITION;
함수 상세 정보 (통합 뷰)
SELECT
p.OBJECT_NAME AS "함수명",
p.PROCEDURE_NAME,
a.ARGUMENT_NAME AS "파라미터명",
a.POSITION AS "순서",
a.DATA_TYPE AS "데이터타입",
a.IN_OUT AS "입출력",
a.DEFAULT_VALUE AS "기본값"
FROM ALL_PROCEDURES p
LEFT JOIN ALL_ARGUMENTS a
ON p.OBJECT_NAME = a.OBJECT_NAME
WHERE p.OBJECT_TYPE = 'FUNCTION'
AND p.OBJECT_NAME = UPPER('함수명')
ORDER BY a.POSITION;
3. 함수 소스 코드 조회
전체 소스 코드 보기
SELECT
LINE,
TEXT
FROM ALL_SOURCE
WHERE NAME = UPPER('함수명')
AND TYPE = 'FUNCTION'
ORDER BY LINE;
소스 코드를 하나의 문자열로 조회
SELECT
LISTAGG(TEXT, '') WITHIN GROUP (ORDER BY LINE) AS SOURCE_CODE
FROM USER_SOURCE
WHERE NAME = UPPER('함수명')
AND TYPE = 'FUNCTION';
특정 키워드를 포함한 함수 찾기
SELECT DISTINCT
NAME AS "함수명",
COUNT(*) AS "매칭라인수"
FROM ALL_SOURCE
WHERE TYPE = 'FUNCTION'
AND UPPER(TEXT) LIKE '%키워드%'
GROUP BY NAME
ORDER BY COUNT(*) DESC;
실무 활용:
- 특정 테이블을 사용하는 함수 찾기
- 특정 함수를 호출하는 다른 함수 찾기
- 하드코딩된 값 찾기
4. 함수 성능 분석
SQL 내에서 호출된 함수 성능 확인
SELECT
sql_text,
executions AS "실행횟수",
ROUND(elapsed_time/1000000, 2) AS "총소요시간(초)",
ROUND(elapsed_time/executions/1000000, 4) AS "평균소요시간(초)",
ROUND(cpu_time/1000000, 2) AS "CPU시간(초)"
FROM v$sql
WHERE UPPER(sql_text) LIKE '%함수명%'
AND executions > 0
ORDER BY elapsed_time DESC;
함수 호출 빈도 분석
-- SQL 문장에서 함수 호출 빈도
SELECT
sql_text,
executions,
(LENGTH(sql_text) - LENGTH(REPLACE(UPPER(sql_text), UPPER('함수명'), '')))
/ LENGTH('함수명') AS "함수호출추정횟수"
FROM v$sql
WHERE UPPER(sql_text) LIKE '%함수명%'
ORDER BY executions DESC;
느린 함수 식별
-- 소스 코드 길이로 복잡도 추정
SELECT
NAME AS "함수명",
COUNT(*) AS "코드라인수",
MAX(LINE) AS "최대라인번호"
FROM USER_SOURCE
WHERE TYPE = 'FUNCTION'
GROUP BY NAME
HAVING COUNT(*) > 100 -- 100줄 이상
ORDER BY COUNT(*) DESC;
5. DETERMINISTIC 함수 관리
DETERMINISTIC 속성 확인
DETERMINISTIC 함수는 같은 입력에 대해 항상 같은 결과를 반환하므로 오라클이 결과를 캐싱할 수 있습니다.
-- 소스에서 DETERMINISTIC 키워드 확인
SELECT
NAME AS "함수명",
CASE
WHEN MAX(CASE WHEN UPPER(TEXT) LIKE '%DETERMINISTIC%' THEN 1 ELSE 0 END) = 1
THEN 'YES'
ELSE 'NO'
END AS "DETERMINISTIC"
FROM USER_SOURCE
WHERE TYPE = 'FUNCTION'
GROUP BY NAME
ORDER BY NAME;
DETERMINISTIC 함수 작성 예시
-- ✅ 좋은 예: 순수 계산 함수
CREATE OR REPLACE FUNCTION calculate_tax(
p_amount IN NUMBER
) RETURN NUMBER
DETERMINISTIC
IS
BEGIN
RETURN p_amount * 0.1; -- 항상 같은 결과
END;
/
-- ❌ 나쁜 예: 시간 의존적 함수
CREATE OR REPLACE FUNCTION get_current_discount(
p_amount IN NUMBER
) RETURN NUMBER
DETERMINISTIC -- 잘못된 사용!
IS
BEGIN
IF SYSDATE BETWEEN '01-JAN-23' AND '31-DEC-23' THEN
RETURN p_amount * 0.2;
ELSE
RETURN p_amount * 0.1;
END IF;
END;
/
DETERMINISTIC 사용 조건:
- 입력 파라미터만으로 결과가 결정
- 데이터베이스 조회 없음
- 시스템 함수(SYSDATE, USER 등) 사용 없음
- 시퀀스 사용 없음
6. 함수 의존성 및 영향도 분석
함수가 참조하는 객체 확인
SELECT
NAME AS "함수명",
TYPE AS "타입",
REFERENCED_OWNER AS "참조스키마",
REFERENCED_NAME AS "참조객체",
REFERENCED_TYPE AS "참조타입",
REFERENCED_LINK_NAME AS "DB링크"
FROM USER_DEPENDENCIES
WHERE NAME = UPPER('함수명')
AND TYPE = 'FUNCTION'
ORDER BY REFERENCED_TYPE, REFERENCED_NAME;
함수를 참조하는 객체 확인 (역방향)
SELECT
NAME AS "참조하는객체",
TYPE AS "객체타입",
REFERENCED_NAME AS "함수명"
FROM USER_DEPENDENCIES
WHERE REFERENCED_NAME = UPPER('함수명')
AND REFERENCED_TYPE = 'FUNCTION'
ORDER BY TYPE, NAME;
테이블 변경 시 영향받는 함수 찾기
SELECT DISTINCT
d.NAME AS "영향받는함수",
d.TYPE AS "객체타입",
d.REFERENCED_NAME AS "의존테이블"
FROM USER_DEPENDENCIES d
WHERE d.REFERENCED_NAME = UPPER('테이블명')
AND d.REFERENCED_TYPE = 'TABLE'
AND d.TYPE = 'FUNCTION'
ORDER BY d.NAME;
함수 의존성 체인 분석
-- 3단계 의존성까지 추적
WITH dep_tree AS (
-- Level 1: 직접 의존성
SELECT
NAME AS func_name,
REFERENCED_NAME AS depends_on,
1 AS depth
FROM USER_DEPENDENCIES
WHERE NAME = UPPER('함수명')
AND TYPE = 'FUNCTION'
UNION ALL
-- Level 2: 간접 의존성
SELECT
dt.func_name,
d.REFERENCED_NAME,
2
FROM dep_tree dt
JOIN USER_DEPENDENCIES d
ON dt.depends_on = d.NAME
WHERE dt.depth = 1
AND d.TYPE = 'FUNCTION'
UNION ALL
-- Level 3
SELECT
dt.func_name,
d.REFERENCED_NAME,
3
FROM dep_tree dt
JOIN USER_DEPENDENCIES d
ON dt.depends_on = d.NAME
WHERE dt.depth = 2
AND d.TYPE = 'FUNCTION'
)
SELECT DISTINCT
func_name AS "함수명",
depends_on AS "의존객체",
depth AS "의존깊이"
FROM dep_tree
ORDER BY depth, depends_on;
7. 함수 작성 Best Practices
7.1 명명 규칙
-- 권장 명명 규칙
-- FN_[동사]_[명사] 또는 GET_[명사], CALC_[명사]
-- 예시:
-- - FN_GET_EMPLOYEE_NAME
-- - FN_CALC_TAX
-- - FN_CHECK_VALID_DATE
-- - GET_DEPARTMENT_TOTAL
7.2 RESULT_CACHE 활용
Oracle 11g 이상에서는 RESULT_CACHE를 사용하여 함수 결과를 메모리에 캐싱할 수 있습니다.
-- ✅ 좋은 예: 자주 호출되고 변경이 드문 데이터
CREATE OR REPLACE FUNCTION get_department_name(
p_dept_id IN NUMBER
) RETURN VARCHAR2
RESULT_CACHE
IS
v_dept_name VARCHAR2(100);
BEGIN
SELECT department_name
INTO v_dept_name
FROM departments
WHERE department_id = p_dept_id;
RETURN v_dept_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
RESULT_CACHE 사용 조건:
- 함수가 자주 호출됨
- 입력값 조합이 제한적
- 참조하는 데이터가 자주 변경되지 않음
- SELECT 문만 있고 DML이 없음
7.3 예외 처리 패턴
-- ✅ 좋은 예: 명확한 예외 처리
CREATE OR REPLACE FUNCTION get_employee_salary(
p_emp_id IN NUMBER
) RETURN NUMBER
IS
v_salary NUMBER;
BEGIN
SELECT salary
INTO v_salary
FROM employees
WHERE employee_id = p_emp_id;
RETURN v_salary;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- 로그 기록 또는 기본값 반환
RETURN 0;
WHEN TOO_MANY_ROWS THEN
-- 데이터 정합성 문제
RAISE_APPLICATION_ERROR(-20001,
'직원 ID ' || p_emp_id || '에 대한 중복 데이터 존재');
WHEN OTHERS THEN
-- 예상치 못한 오류
RAISE_APPLICATION_ERROR(-20002,
'함수 실행 오류: ' || SQLERRM);
END;
/
7.4 NULL 처리
-- ✅ 좋은 예: NULL 안전 함수
CREATE OR REPLACE FUNCTION calculate_discount(
p_amount IN NUMBER,
p_rate IN NUMBER DEFAULT 0
) RETURN NUMBER
IS
BEGIN
-- NULL 체크
IF p_amount IS NULL THEN
RETURN NULL;
END IF;
IF p_rate IS NULL OR p_rate < 0 THEN
RETURN p_amount; -- 할인 없음
END IF;
RETURN p_amount * (1 - p_rate);
END;
/
7.5 함수 순수성 유지 (Purity)
-- ✅ 좋은 예: 순수 함수 (사이드 이펙트 없음)
CREATE OR REPLACE FUNCTION format_phone_number(
p_phone IN VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN SUBSTR(p_phone, 1, 3) || '-' ||
SUBSTR(p_phone, 4, 4) || '-' ||
SUBSTR(p_phone, 8, 4);
END;
/
-- ❌ 나쁜 예: 사이드 이펙트 있음
CREATE OR REPLACE FUNCTION log_and_return(
p_value IN NUMBER
) RETURN NUMBER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- 함수에서 데이터 변경 (안티패턴)
INSERT INTO audit_log VALUES (SYSDATE, p_value);
COMMIT;
RETURN p_value;
END;
/
7.6 성능을 위한 SQL 최적화
-- ❌ 나쁜 예: 함수 내에서 반복 쿼리
CREATE OR REPLACE FUNCTION get_total_orders_bad(
p_customer_id IN NUMBER
) RETURN NUMBER
IS
v_total NUMBER := 0;
BEGIN
FOR rec IN (SELECT order_id FROM orders WHERE customer_id = p_customer_id) LOOP
SELECT amount INTO v_total
FROM order_details
WHERE order_id = rec.order_id;
END LOOP;
RETURN v_total;
END;
/
-- ✅ 좋은 예: 단일 쿼리로 처리
CREATE OR REPLACE FUNCTION get_total_orders_good(
p_customer_id IN NUMBER
) RETURN NUMBER
IS
v_total NUMBER;
BEGIN
SELECT SUM(od.amount)
INTO v_total
FROM orders o
JOIN order_details od ON o.order_id = od.order_id
WHERE o.customer_id = p_customer_id;
RETURN NVL(v_total, 0);
END;
/
8. 함수 vs 프로시저 선택 가이드
언제 함수를 사용할까?
| 상황 | 함수 | 프로시저 |
|---|---|---|
| SQL 쿼리 내에서 호출 | ✅ | ❌ |
| 단일 값 반환 | ✅ | △ (OUT 파라미터) |
| SELECT 문에서 사용 | ✅ | ❌ |
| DML 수행 (INSERT/UPDATE/DELETE) | ❌ 권장하지 않음 | ✅ |
| 복잡한 비즈니스 로직 | △ | ✅ |
| 트랜잭션 제어 (COMMIT/ROLLBACK) | ❌ | ✅ |
함수 사용이 적합한 경우
-- ✅ Case 1: SQL에서 직접 사용
SELECT
employee_id,
first_name,
FN_GET_DEPARTMENT_NAME(department_id) AS dept_name,
FN_CALC_TAX(salary) AS tax_amount
FROM employees;
-- ✅ Case 2: 재사용 가능한 계산 로직
SELECT
product_id,
price,
FN_APPLY_DISCOUNT(price, discount_rate) AS discounted_price
FROM products;
-- ✅ Case 3: 데이터 변환/포맷팅
SELECT
order_id,
FN_FORMAT_DATE(order_date, 'YYYY-MM-DD') AS formatted_date
FROM orders;
프로시저 사용이 적합한 경우
-- ✅ Case 1: 복잡한 비즈니스 로직
BEGIN
SP_PROCESS_MONTHLY_SALARY(
p_year => 2024,
p_month => 12
);
END;
/
-- ✅ Case 2: 다중 DML 작업
BEGIN
SP_TRANSFER_EMPLOYEE(
p_emp_id => 100,
p_new_dept_id => 50,
p_effective_date => SYSDATE
);
END;
/
9. 함수 성능 최적화 체크리스트
9.1 PARALLEL_ENABLE 사용
대량 데이터 처리 시 병렬 실행을 허용합니다.
CREATE OR REPLACE FUNCTION calculate_bonus(
p_salary IN NUMBER
) RETURN NUMBER
PARALLEL_ENABLE
IS
BEGIN
RETURN p_salary * 0.1;
END;
/
-- 병렬 실행 가능
SELECT
employee_id,
calculate_bonus(salary) AS bonus
FROM employees;
9.2 함수 기반 인덱스 (FBI)
자주 사용되는 함수에 대해 인덱스를 생성합니다.
-- 함수 생성
CREATE OR REPLACE FUNCTION get_upper_name(
p_name IN VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN UPPER(p_name);
END;
/
-- 함수 기반 인덱스 생성
CREATE INDEX idx_upper_name
ON employees(get_upper_name(first_name));
-- 인덱스 활용 쿼리
SELECT *
FROM employees
WHERE get_upper_name(first_name) = 'JOHN';
9.3 불필요한 함수 호출 제거
-- ❌ 나쁜 예: 같은 함수를 여러 번 호출
SELECT
employee_id,
FN_GET_DEPT_NAME(department_id),
FN_GET_DEPT_LOCATION(department_id),
FN_GET_DEPT_MANAGER(department_id)
FROM employees;
-- ✅ 좋은 예: JOIN으로 한 번에 조회
SELECT
e.employee_id,
d.department_name,
d.location,
d.manager_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;
10. 함수 모니터링 및 관리
INVALID 함수 찾기 및 재컴파일
-- INVALID 함수 목록
SELECT
OBJECT_NAME AS "함수명",
STATUS AS "상태",
LAST_DDL_TIME AS "최종수정일"
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
AND STATUS = 'INVALID'
ORDER BY LAST_DDL_TIME DESC;
-- 컴파일 오류 확인
SELECT
LINE,
POSITION,
TEXT AS "오류내용"
FROM USER_ERRORS
WHERE NAME = UPPER('함수명')
AND TYPE = 'FUNCTION'
ORDER BY SEQUENCE;
-- 재컴파일 스크립트 생성
SELECT 'ALTER FUNCTION ' || OBJECT_NAME || ' COMPILE;'
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
AND STATUS = 'INVALID';
함수 사용 현황 모니터링
-- 어떤 프로그램에서 함수를 사용하는지 확인
SELECT DISTINCT
d.NAME AS "호출하는객체",
d.TYPE AS "객체타입",
o.STATUS AS "상태"
FROM USER_DEPENDENCIES d
JOIN USER_OBJECTS o ON d.NAME = o.OBJECT_NAME
WHERE d.REFERENCED_NAME = UPPER('함수명')
AND d.REFERENCED_TYPE = 'FUNCTION'
ORDER BY d.TYPE, d.NAME;
함수 백업 (DDL 추출)
-- 개별 함수 DDL
SELECT DBMS_METADATA.GET_DDL('FUNCTION', '함수명') AS ddl
FROM DUAL;
-- 모든 함수 DDL 추출
SELECT DBMS_METADATA.GET_DDL('FUNCTION', OBJECT_NAME) AS ddl
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION'
ORDER BY OBJECT_NAME;
11. 함수 테스트 및 디버깅
단위 테스트 템플릿
-- 테스트 케이스 테이블
CREATE TABLE function_test_cases (
test_id NUMBER PRIMARY KEY,
function_name VARCHAR2(100),
test_case VARCHAR2(500),
input_params VARCHAR2(4000),
expected_output VARCHAR2(4000),
actual_output VARCHAR2(4000),
test_result VARCHAR2(10),
test_date DATE
);
-- 테스트 실행 예시
DECLARE
v_result NUMBER;
v_expected NUMBER := 1000;
BEGIN
-- 함수 실행
v_result := FN_CALC_TAX(10000);
-- 결과 검증
IF v_result = v_expected THEN
DBMS_OUTPUT.PUT_LINE('✅ 테스트 성공');
ELSE
DBMS_OUTPUT.PUT_LINE('❌ 테스트 실패: 예상=' || v_expected ||
', 실제=' || v_result);
END IF;
END;
/
디버깅을 위한 로깅
-- 로그 테이블 생성
CREATE TABLE function_debug_log (
log_id NUMBER PRIMARY KEY,
function_name VARCHAR2(100),
log_level VARCHAR2(20),
log_message CLOB,
log_date TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE SEQUENCE seq_debug_log START WITH 1;
-- 로깅이 포함된 함수 예시
CREATE OR REPLACE FUNCTION calculate_with_log(
p_amount IN NUMBER
) RETURN NUMBER
IS
v_result NUMBER;
v_debug_enabled BOOLEAN := TRUE; -- 개발 시에만 TRUE
BEGIN
IF v_debug_enabled THEN
INSERT INTO function_debug_log VALUES (
seq_debug_log.NEXTVAL,
'CALCULATE_WITH_LOG',
'INFO',
'Input: ' || p_amount,
SYSTIMESTAMP
);
END IF;
-- 비즈니스 로직
v_result := p_amount * 1.1;
IF v_debug_enabled THEN
INSERT INTO function_debug_log VALUES (
seq_debug_log.NEXTVAL,
'CALCULATE_WITH_LOG',
'INFO',
'Output: ' || v_result,
SYSTIMESTAMP
);
COMMIT; -- 로그는 별도 커밋
END IF;
RETURN v_result;
END;
/
12. 실무 패턴 모음
패턴 1: Safe Division (0으로 나누기 방지)
CREATE OR REPLACE FUNCTION safe_divide(
p_numerator IN NUMBER,
p_denominator IN NUMBER,
p_default IN NUMBER DEFAULT NULL
) RETURN NUMBER
DETERMINISTIC
IS
BEGIN
IF p_denominator = 0 OR p_denominator IS NULL THEN
RETURN p_default;
END IF;
RETURN p_numerator / p_denominator;
END;
/
-- 사용 예
SELECT
product_id,
safe_divide(total_sales, total_orders, 0) AS avg_order_value
FROM products;
패턴 2: String Aggregation
CREATE OR REPLACE FUNCTION get_employee_skills(
p_emp_id IN NUMBER
) RETURN VARCHAR2
IS
v_skills VARCHAR2(4000);
BEGIN
SELECT LISTAGG(skill_name, ', ') WITHIN GROUP (ORDER BY skill_name)
INTO v_skills
FROM employee_skills
WHERE employee_id = p_emp_id;
RETURN v_skills;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
패턴 3: Date Range Validation
CREATE OR REPLACE FUNCTION is_date_in_range(
p_check_date IN DATE,
p_start_date IN DATE,
p_end_date IN DATE
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
IF p_check_date BETWEEN p_start_date AND p_end_date THEN
RETURN 'Y';
ELSE
RETURN 'N';
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN 'N';
END;
/
패턴 4: Hierarchy Path Builder
CREATE OR REPLACE FUNCTION get_org_path(
p_emp_id IN NUMBER
) RETURN VARCHAR2
IS
v_path VARCHAR2(4000);
BEGIN
SELECT LTRIM(SYS_CONNECT_BY_PATH(department_name, ' > '), ' > ')
INTO v_path
FROM departments
START WITH department_id = (
SELECT department_id
FROM employees
WHERE employee_id = p_emp_id
)
CONNECT BY PRIOR parent_department_id = department_id;
RETURN v_path;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
13. 엑셀 추출용 종합 리포트
-- 함수 관리 리포트 (문서화용)
SELECT
ROWNUM AS "NO",
o.OBJECT_NAME AS "함수명",
o.STATUS AS "상태",
TO_CHAR(o.CREATED, 'YYYY-MM-DD') AS "생성일",
TO_CHAR(o.LAST_DDL_TIME, 'YYYY-MM-DD') AS "수정일",
(SELECT COUNT(*)
FROM USER_SOURCE s
WHERE s.NAME = o.OBJECT_NAME
AND s.TYPE = 'FUNCTION') AS "코드라인수",
(SELECT COUNT(*)
FROM USER_DEPENDENCIES d
WHERE d.NAME = o.OBJECT_NAME
AND d.TYPE = 'FUNCTION') AS "의존성수",
CASE
WHEN EXISTS (
SELECT 1 FROM USER_SOURCE s
WHERE s.NAME = o.OBJECT_NAME
AND UPPER(s.TEXT) LIKE '%DETERMINISTIC%'
) THEN 'Y'
ELSE 'N'
END AS "DETERMINISTIC",
CASE
WHEN EXISTS (
SELECT 1 FROM USER_SOURCE s
WHERE s.NAME = o.OBJECT_NAME
AND UPPER(s.TEXT) LIKE '%RESULT_CACHE%'
) THEN 'Y'
ELSE 'N'
END AS "RESULT_CACHE"
FROM USER_OBJECTS o
WHERE o.OBJECT_TYPE = 'FUNCTION'
ORDER BY o.OBJECT_NAME;
14. 마치며
오라클 함수는 SQL과 PL/SQL의 강력한 결합을 가능하게 하는 핵심 기능입니다. 이 가이드의 내용을 활용하면:
- ✅ 함수를 체계적으로 관리하고 모니터링할 수 있습니다
- ✅ 성능 최적화를 위한 명확한 지침을 얻을 수 있습니다
- ✅ 함수와 프로시저 중 적절한 선택을 할 수 있습니다
- ✅ 의존성 관리를 통해 시스템 안정성을 높일 수 있습니다
핵심 권장사항:
- 함수는 순수하게 (사이드 이펙트 없이) 작성
- DETERMINISTIC, RESULT_CACHE를 적절히 활용
- SQL 내 함수 호출을 최소화 (JOIN 우선 고려)
- 정기적인 성능 모니터링과 리팩토링
- 명확한 명명 규칙과 문서화
반응형