JOIN 없이도 가능하다? SQL에서 서브쿼리로 해결하는 3가지 실무 상황

Posted by heoncode
2025. 4. 11. 15:55 SQL 기초 정리
728x90
SMALL

SQL에서 데이터를 합치기 위해 가장 먼저 떠오르는 키워드는 JOIN입니다. 하지만 모든 상황에서 JOIN이 꼭 필요한 것은 아닙니다. 실무에서는 JOIN을 쓰기 복잡하거나 성능상 불리할 때, 서브쿼리(Subquery)를 이용해 문제를 해결하기도 합니다. 이번 글에서는 JOIN 없이 서브쿼리만으로 해결할 수 있는 3가지 실무 상황을 소개합니다.

1. 특정 조건에 해당하는 값만 가져올 때

예를 들어 각 사원의 부서 이름을 출력하고 싶은데, 특정 부서만 필터링하고 싶다면 JOIN 없이도 다음과 같이 서브쿼리로 처리할 수 있습니다.

SELECT emp_name,
       (SELECT dept_name
        FROM department d
        WHERE d.dept_id = e.dept_id)
       AS dept_name
FROM employee e
WHERE e.dept_id IN (10, 20);

JOIN을 사용하지 않고도 서브쿼리로 필요한 부서명을 함께 출력할 수 있습니다.

2. 조건 비교를 위해 필요한 보조 데이터를 가져올 때

각 제품의 가격이 전체 평균보다 높은 제품만 찾고 싶다면, 아래와 같이 서브쿼리를 WHERE 절에 활용할 수 있습니다.

SELECT product_name, price
FROM product
WHERE price > (SELECT AVG(price) FROM product);

이처럼 전체 집계 결과와 비교할 때도 서브쿼리를 사용하면 JOIN 없이 해결할 수 있습니다.

3. 최근 거래 내역 등 특정 조건의 1건만 가져올 때

각 고객의 최근 주문 내역을 보고 싶다면, 관련 테이블을 JOIN하기보다 상관 서브쿼리를 사용할 수 있습니다.

SELECT c.customer_id,
       (SELECT order_date
        FROM orders o
        WHERE o.customer_id = c.customer_id
        ORDER BY order_date DESC
        FETCH FIRST 1 ROW ONLY)
       AS latest_order
FROM customer c;

이 방식은 고객 수가 많아도 간결하고 효율적인 쿼리를 작성할 수 있게 해줍니다.


JOIN은 강력한 도구지만, 서브쿼리는 구조를 단순화하거나 불필요한 조인을 줄이는 데 유용하게 쓰일 수 있습니다. 실무에서는 복잡한 조인보다 오히려 서브쿼리로 명확하게 표현하는 것이 유지보수나 성능 측면에서 더 나은 선택이 되는 경우도 많습니다.

#SQL #서브쿼리 #JOIN #실무팁 #쿼리작성 #DB초보 #SQL기초

728x90
LIST

DISTINCT vs GROUP BY – 결과는 같아도 목적은 다르다

Posted by heoncode
2025. 4. 11. 11:20 SQL 기초 정리
728x90
SMALL

SQL에서 중복된 값을 제거하기 위해 DISTINCT를 사용하고, 데이터를 그룹화하기 위해 GROUP BY를 사용합니다. 하지만 때로는 두 문장이 같은 결과를 반환하기도 하여, 어떤 걸 써야 할지 혼란스러울 수 있습니다. 이 글에서는 두 구문의 차이를 명확하게 정리합니다.

DISTINCT: 단순히 중복된 행을 제거

DISTINCTSELECT 절에서 중복된 행을 제거하는 용도로 사용됩니다. 특정 컬럼 또는 여러 컬럼 조합이 중복일 경우, 하나만 남기고 제거합니다.

예시:

SELECT DISTINCT dept_id 
FROM employees;

→ 부서 ID가 중복되는 경우 하나만 표시됩니다.

여러 컬럼을 기준으로도 중복 제거가 가능합니다:

SELECT DISTINCT dept_id, job 
FROM employees;

→ 부서 ID와 직책 조합이 동일한 경우, 하나만 남깁니다.

GROUP BY: 데이터를 그룹으로 묶은 후 집계

GROUP BY데이터를 그룹화한 뒤, 집계 함수(SUM, COUNT 등)를 함께 사용할 때 주로 사용됩니다. 단순히 중복 제거가 목적이라면 DISTINCT가 더 적절하지만, 그룹별 통계가 필요하다면 GROUP BY를 사용해야 합니다.

예시:

SELECT dept_id, COUNT(*) 
FROM employees
GROUP BY dept_id;

→ 부서별로 몇 명의 직원이 있는지를 보여줍니다.

만약 집계 함수 없이 GROUP BY만 사용한다면 DISTINCT와 유사한 결과가 나오지만, 문장의 의미는 다릅니다.

예시:

SELECT dept_id 
FROM employees 
GROUP BY dept_id;

SELECT DISTINCT dept_id FROM employees;와 결과는 같지만, 의미상 그룹화입니다.


정리

목적 사용 구문
단순 중복 제거 DISTINCT
집계 또는 그룹 통계 GROUP BY

실무 팁: 결과만 보고 두 문장을 혼동하면 안 됩니다. 왜 이 구문을 쓰는지, 목적에 따라 구문을 선택하세요.


#SQL #DISTINCT #GROUPBY #중복제거 #집계함수 #기초정리 #실무팁 #데이터분석

728x90
LIST

WHERE 절과 HAVING 절, 헷갈리는 이유와 실무 기준 정리

Posted by heoncode
2025. 4. 11. 08:41 SQL 기초 정리
728x90
SMALL

SQL에서 조건을 설정할 수 있는 절은 대표적으로 WHEREHAVING이 있습니다. 둘 다 데이터를 필터링하는 기능이지만, 사용하는 시점과 용도에는 분명한 차이가 있습니다. 실무에서도 종종 이 둘을 혼용하거나, 쿼리가 잘못 동작하는 원인이 되기도 합니다.

WHERE 절: 집계 전 데이터를 필터링

WHERE 절은 그룹화나 집계가 수행되기 전에 데이터를 필터링합니다. 즉, 원본 테이블에서 조건을 걸고 필요한 행만 남긴 후에 GROUP BY, SUM, AVG 등의 집계 함수가 동작합니다.

예시:

SELECT dept_id, COUNT(*) 
FROM employees
WHERE job = 'MANAGER'
GROUP BY dept_id;

→ 여기서 WHERE은 "직책이 MANAGER인 직원"만 대상으로 그룹화합니다.

HAVING 절: 집계 이후 그룹 필터링

HAVING 절은 GROUP BY 이후 집계된 결과에 조건을 거는 데 사용합니다. WHERE과 달리 집계 함수(COUNT, SUM, 등)를 사용할 수 있습니다.

예시:

SELECT dept_id, COUNT(*) AS cnt
FROM employees
GROUP BY dept_id
HAVING COUNT(*) >= 5;

→ 모든 부서를 그룹화한 후, 직원 수가 5명 이상인 부서만 결과로 출력됩니다.

둘 다 쓰는 경우

두 절을 함께 쓰는 것도 가능합니다. 이때는 WHERE이 먼저, HAVING이 나중에 적용됩니다.

SELECT dept_id, COUNT(*) 
FROM employees
WHERE job = 'MANAGER'
GROUP BY dept_id
HAVING COUNT(*) >= 2;

→ MANAGER만 대상으로 부서별 그룹을 만들고, 그중에서 2명 이상인 부서만 필터링합니다.


실무 팁으로 기억하면 좋습니다:

  • WHERE은 개별 행을 필터링
  • HAVING은 집계 결과를 필터링

이 원칙만 기억하면 두 조건절을 헷갈릴 일이 줄어듭니다.


#SQL #WHERE절 #HAVING절 #조건절 #GROUPBY #집계함수 #기초정리 #실무팁

728x90
LIST

LEFT JOIN 결과가 예상과 다를 때? 누락된 데이터의 진짜 원인

Posted by heoncode
2025. 4. 11. 00:38 SQL 기초 정리
728x90
SMALL

SQL에서 LEFT JOIN왼쪽 테이블의 모든 데이터를 기준으로 오른쪽 테이블과 연결해주는 기능입니다. 하지만 실무에서는 종종 LEFT JOIN을 썼는데도 결과가 예상보다 적게 나오는 일이 발생합니다. 이 글에서는 그런 상황에서 확인해야 할 3가지 핵심 원인을 소개합니다.

1. WHERE 절 조건이 JOIN 결과를 제한한다

아래 쿼리를 살펴봅시다:

SELECT *
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id
WHERE d.location = 'SEOUL';

의도는 모든 직원 정보를 보고 싶은 것인데, 이 쿼리는 d.location이 NULL인 직원(=부서가 없는 직원)은 제외됩니다. 이는 WHERE 절이 조인 이후에 적용되기 때문입니다.

→ 해결책은 조건을 JOIN 안에 넣는 것입니다:

SELECT *
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id AND d.location = 'SEOUL';

이렇게 하면 부서가 없는 직원도 빠지지 않습니다.

2. JOIN 조건이 누락되거나 잘못되었다

SELECT *
FROM employees e
LEFT JOIN departments d ON e.name = d.name;

이런 식으로 정확한 조인 조건 없이 컬럼 이름만 같은 걸 기준으로 조인하면 원하지 않는 결과가 나옵니다. 항상 기본키-외래키 관계 또는 고유한 값을 기준으로 조인해야 합니다.

3. 중첩 JOIN과 서브쿼리에서 발생하는 필터링

복잡한 쿼리일수록 LEFT JOIN이 서브쿼리 내부에 있거나 INNER JOIN과 함께 쓰이면서 무의식적으로 결과가 줄어들 수 있습니다. 쿼리 구조를 항상 시각화하면서 데이터 흐름을 따져보는 습관이 필요합니다.


LEFT JOIN은 단순한 듯 보여도 실무에서는 자주 함정에 빠지는 구간입니다. 특히 WHERE 절의 위치나 조인 조건에 따라 결과가 확 달라질 수 있으니 항상 주의 깊게 쿼리를 작성해야 합니다.


#SQL #JOIN #LEFTJOIN #외부조인 #누락 #쿼리디버깅 #기초정리 #실무팁

728x90
LIST

SELECT *를 쓰면 왜 안 좋을까? 실무에서 컬럼을 명시하는 이유

Posted by heoncode
2025. 4. 10. 17:11 SQL 기초 정리
728x90
SMALL

SQL을 처음 배울 때 가장 먼저 접하게 되는 문장이 SELECT * FROM 테이블명입니다. 모든 컬럼을 조회할 수 있어 편리하지만, 실무에서는 대부분의 경우 SELECT * 사용을 지양합니다. 왜 그럴까요?

1. 성능 저하

SELECT *는 테이블의 모든 컬럼을 조회하므로, 필요한 컬럼만 선택한 경우보다 훨씬 많은 데이터를 읽게 됩니다. 특히 테이블에 수십 개의 컬럼이 있을 경우, 불필요한 IO 작업이 증가하고 네트워크 부하도 커지게 됩니다.

2. 유지보수의 어려움

테이블 구조가 변경되면 SELECT *의 결과도 바뀔 수 있습니다. 예를 들어 새 컬럼이 추가되었을 때, 의도치 않게 쿼리 결과가 달라져 에러가 발생하거나 보고서 양식이 깨지는 등의 문제가 생길 수 있습니다.

3. 가독성과 명확성 부족

어떤 컬럼이 사용되는지 코드만 보고는 알 수 없습니다. 반면 컬럼을 명시하면 해당 쿼리가 어떤 데이터를 다루는지 명확히 알 수 있어 유지보수와 협업에 유리합니다.

4. 인덱스 무효화 가능성

인덱스를 활용하는 쿼리의 경우, SELECT *로 인해 인덱스만으로는 데이터를 충족할 수 없어 테이블 전체를 읽는 Full Table Scan이 발생할 수 있습니다.

정리하자면

가능한 한 필요한 컬럼만 명시하는 습관을 들이는 것이 좋습니다. 예를 들어:

SELECT emp_id, emp_name, salary
FROM employees;

이렇게 쓰면 성능도 좋고, 명확성도 올라가며 유지보수도 쉬워집니다. SELECT *는 학습 단계에선 도움이 되지만, 실무에선 피해야 할 문장입니다.


#SQL #SELECT문 #SELECT별표 #쿼리작성 #성능 #실무팁 #데이터베이스 #기초정리

728x90
LIST

NULL은 0이 아니다! SQL에서 NULL이 가진 의미와 주의점

Posted by heoncode
2025. 4. 10. 11:34 SQL 기초 정리
728x90
SMALL

SQL을 처음 접할 때 가장 혼동하기 쉬운 개념 중 하나가 바로 NULL입니다. 많은 분들이 NULL을 숫자 0이나 빈 문자열로 오해하지만, 실제로는 값이 존재하지 않음을 의미합니다.

NULL은 어떤 의미인가요?

  • NULL값이 존재하지 않음을 나타냅니다.
  • 숫자 0(0)은 실제 값이고, NULL값 자체가 없음입니다.
  • 빈 문자열('')도 NULL과 다릅니다. 빈 문자열은 값이지만, 비어있는 값일 뿐입니다.

NULL을 비교할 때 주의할 점

일반적인 비교 연산자(=, !=)로는 NULL 값을 정확히 비교할 수 없습니다. 예를 들어 다음 쿼리는 아무 결과도 반환하지 않습니다.

SELECT * FROM employees WHERE commission_pct = NULL;

이유는 NULL = NULL은 참이 아니라 알 수 없음(UNKNOWN)이 되기 때문입니다. NULL 비교는 반드시 IS NULL 또는 IS NOT NULL을 사용해야 합니다.

SELECT * FROM employees WHERE commission_pct IS NULL;

집계 함수와 NULL

  • COUNT(*)는 모든 행을 세지만
    COUNT(column)은 해당 컬럼이 NULL이 아닌 값만 셉니다.
  • SUM, AVG, MAX, MIN 같은 집계 함수도 NULL은 무시하고 계산합니다.

실무에서 자주 발생하는 실수

  • 조건절에 = NULL 사용 → 항상 결과가 없음
  • 조인 시 NULL값이 있는 컬럼 누락 → 원하는 결과 누락
  • 정렬(SORT) 결과가 예상과 다름 → NULLS FIRST 또는 NULLS LAST 명시 필요

SQL에서 NULL은 단순한 "빈 값"이 아닌, 존재하지 않는 상태로 간주됩니다. 쿼리 작성 시 NULL의 의미를 정확히 이해하고 조건절이나 집계 함수에서 적절히 처리하는 것이 매우 중요합니다.


#SQL #NULL #값비교 #ISNULL #쿼리실수 #기초정리 #데이터베이스

728x90
LIST

WHERE 절 조건의 순서가 성능에 영향을 줄까?

Posted by heoncode
2025. 4. 10. 09:10 SQL 기초 정리
728x90
SMALL

SQL 쿼리를 작성할 때 WHERE 절 안의 조건 순서를 신경 써야 할까요? 예를 들어 다음 두 쿼리는 조건 순서만 다를 뿐 동일한 결과를 반환합니다.

SELECT * FROM employees
WHERE salary > 5000 AND department_id = 10;

SELECT * FROM employees
WHERE department_id = 10 AND salary > 5000;

논리적으로는 동일하지만, 실행 성능은 달라질 수 있습니다. 그 이유는 바로 오라클 옵티마이저(Optimizer)가 실행 계획을 생성할 때 조건 순서를 고려하기 때문입니다.

옵티마이저는 어떻게 조건을 처리할까?

오라클 옵티마이저는 통계 정보, 인덱스 유무, 조건의 선택도 등을 종합적으로 판단해 실행 계획을 수립합니다. 이 과정에서 조건의 순서가 힌트를 줄 수는 있지만, 옵티마이저는 일반적으로 가장 효율적인 조건부터 우선 적용하려 합니다.

즉, 작성 순서보다는 조건의 필터링 효과(선택도)가 중요합니다. 예를 들어 department_id = 10 조건이 훨씬 더 많은 행을 걸러낼 수 있다면, 옵티마이저는 해당 조건을 먼저 적용하는 방향으로 실행 계획을 구성합니다.

실무에서는 어떤 기준으로 정리할까?

  • 조건 순서는 성능에 직접적인 영향을 주지 않을 수 있음
    → 옵티마이저가 최적 조건을 자동으로 판단

  • 다만 인덱스를 활용하려면 조건 순서가 중요할 수 있음
    → 복합 인덱스의 컬럼 순서에 맞춰 WHERE 조건을 작성하는 것이 유리

  • 실행계획(EXPLAIN PLAN)으로 실제 적용된 조건 순서를 확인
    → 예상과 다른 경우 힌트나 인덱스 조정 필요

조건 순서가 항상 성능을 좌우하는 것은 아니지만, 인덱스 구조와 선택도에 맞춰 조건을 구성하면 더 효율적인 쿼리를 만들 수 있습니다.


#SQL #WHERE절 #조건순서 #실행계획 #성능최적화 #쿼리튜닝 #인덱스활용

728x90
LIST

INNER JOIN과 OUTER JOIN, 뭐가 다를까? 실무에서 꼭 알아야 할 차이점

Posted by heoncode
2025. 4. 10. 00:57 SQL 기초 정리
728x90
SMALL

INNER JOIN과 OUTER JOIN, 뭐가 다를까? 실무에서 꼭 알아야 할 차이점

SQL에서 여러 테이블의 데이터를 함께 조회할 때 JOIN을 사용합니다. 하지만 JOIN에는 여러 종류가 있어서 처음 접하는 분들은 헷갈리기 쉽습니다. 특히 INNER JOINOUTER JOIN의 차이를 정확히 이해하는 것은 실무에서 매우 중요합니다. 이번 글에서는 이 두 JOIN의 차이점과 사용 예시를 통해 개념을 확실히 잡아보겠습니다.

1. INNER JOIN – 교집합 찾기

INNER JOIN은 두 테이블에서 공통된 값이 있는 행만 반환합니다. 즉, 양쪽 테이블에 모두 존재하는 데이터만 조회하고, 한쪽에만 있는 데이터는 제외됩니다.

예제:

employees 테이블과 departments 테이블이 있다고 가정해봅시다.

  • employees 테이블:

    employee_id name department_id
    1 철수 10
    2 영희 20
    3 민수 30
  • departments 테이블:

    department_id department_name
    10 인사부
    20 개발부
    40 마케팅부

이제 두 테이블을 department_id를 기준으로 INNER JOIN 해보겠습니다.

SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;

결과:

| name  | department_name |
|-------|-----------------|
| 철수  | 인사부          |
| 영희  | 개발부          |

여기서 민수마케팅부는 각각 다른 테이블에만 존재하므로 결과에서 제외되었습니다.

2. OUTER JOIN – 전체 데이터 조회하기

OUTER JOIN은 한쪽 테이블에만 존재하는 데이터도 포함하여 조회합니다. OUTER JOIN은 다시 LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN으로 나뉩니다.

  • LEFT OUTER JOIN: 왼쪽 테이블의 모든 행을 반환하고, 오른쪽 테이블에 일치하는 데이터가 없으면 NULL을 반환합니다.
  • RIGHT OUTER JOIN: 오른쪽 테이블의 모든 행을 반환하고, 왼쪽 테이블에 일치하는 데이터가 없으면 NULL을 반환합니다.
  • FULL OUTER JOIN: 양쪽 테이블의 모든 행을 반환하며, 일치하는 데이터가 없으면 NULL을 반환합니다.

예제:

위의 employeesdepartments 테이블을 LEFT OUTER JOIN 해보겠습니다.

SELECT e.name, d.department_name
FROM employees e
LEFT OUTER JOIN departments d ON e.department_id = d.department_id;

결과:

| name  | department_name |
|-------|-----------------|
| 철수  | 인사부          |
| 영희  | 개발부          |
| 민수  | NULL            |

민수employees 테이블에는 있지만 departments 테이블에 해당 department_id가 없으므로 department_name이 NULL로 표시됩니다.

✅ 마무리

  • INNER JOIN: 양쪽 테이블에 모두 존재하는 데이터만 조회
  • OUTER JOIN:
    • LEFT OUTER JOIN: 왼쪽 테이블의 모든 데이터와 일치하는 오른쪽 테이블의 데이터 조회
    • RIGHT OUTER JOIN: 오른쪽 테이블의 모든 데이터와 일치하는 왼쪽 테이블의 데이터 조회
    • FULL OUTER JOIN: 양쪽 테이블의 모든 데이터 조회

JOIN을 적절히 사용하면 데이터베이스에서 원하는 정보를 효율적으로 추출할 수 있습니다. 실무에서는 데이터의 특성과 요구사항에 맞게 JOIN을 선택하여 사용해야 합니다.

#SQL #JOIN #INNERJOIN #OUTERJOIN #데이터베이스 #기초문법 #실무팁

728x90
LIST

GROUP BY와 ORDER BY의 차이는 뭘까? 비슷해 보이지만 전혀 다른 역할

Posted by heoncode
2025. 4. 9. 17:13 SQL 기초 정리
728x90
SMALL

GROUP BYORDER BY의 차이는 뭘까? 비슷해 보이지만 전혀 다른 역할

SQL을 처음 배우면 자주 혼동되는 개념 중 하나가 GROUP BYORDER BY입니다. 둘 다 SELECT문에서 자주 사용되며 컬럼 이름을 기준으로 뭔가를 "묶거나 정렬"하는 것 같지만, 실제로는 그 목적과 동작 방식이 완전히 다릅니다. 이번 글에서는 이 두 구문의 차이를 예제와 함께 명확히 정리해 보겠습니다.

1. GROUP BY – 같은 값을 하나의 그룹으로 묶기

GROUP BY는 집계 함수(COUNT, SUM, AVG 등)와 함께 사용되어 같은 값을 가진 행들을 하나의 그룹으로 묶습니다. 예를 들어, 부서별 사원 수를 구하고자 할 때 사용됩니다.

SELECT department_id, COUNT(*) 
FROM employees 
GROUP BY department_id;

위 쿼리는 department_id가 같은 행들을 묶어 각 부서에 몇 명이 있는지 알려줍니다.

✅ 핵심: GROUP BY묶기 (집계 대상 그룹 생성)

2. ORDER BY – 결과를 원하는 순서로 정렬

ORDER BY는 쿼리 결과의 행 순서를 정렬합니다. 오름차순(ASC) 또는 내림차순(DESC)으로 정렬할 수 있으며, 집계와는 아무런 관련이 없습니다.

SELECT employee_id, salary 
FROM employees 
ORDER BY salary DESC;

위 쿼리는 월급이 높은 순으로 직원을 나열하며, 어떤 그룹화도 하지 않습니다.

✅ 핵심: ORDER BY정렬 (출력 순서 제어)

3. 둘을 함께 사용하는 예

GROUP BY로 먼저 그룹을 만든 후, 그 결과를 ORDER BY로 정렬할 수도 있습니다.

SELECT department_id, AVG(salary) AS avg_salary 
FROM employees 
GROUP BY department_id 
ORDER BY avg_salary DESC;

이 쿼리는 부서별 평균 급여를 계산한 뒤, 평균이 높은 부서부터 나열합니다.

✅ 마무리

  • GROUP BY: 집계를 위해 데이터를 묶는 역할
  • ORDER BY: 결과를 정렬하는 역할

두 구문은 비슷해 보이지만 완전히 다른 용도입니다. 실무에서는 이 둘을 함께 사용하는 경우도 많기 때문에 그 차이를 정확히 이해하는 것이 중요합니다.

#SQL #GROUPBY #ORDERBY #정렬 #집계 #SELECT문 #기초문법 #실무팁

728x90
LIST

INDEX RANGE SCAN과 FULL SCAN, 언제 어떤 게 빠를까?

Posted by heoncode
2025. 4. 9. 09:14 오라클 실무 쿼리 튜닝
728x90
SMALL

INDEX RANGE SCAN과 FULL SCAN, 언제 어떤 게 빠를까?

오라클의 실행계획에서 자주 등장하는 INDEX RANGE SCAN과 FULL TABLE SCAN은 단순히 “인덱스가 빠르다”는 기준으로 선택할 수 없습니다. 데이터 양, 인덱스 구조, 조건절 등에 따라 성능 차이는 극적으로 달라질 수 있으며, 실무에서는 오히려 FULL SCAN이 더 나은 선택일 때도 있습니다. 이번 글에서는 두 방식의 차이와 선택 기준을 살펴보겠습니다.

1. INDEX RANGE SCAN – 인덱스를 이용한 범위 검색

INDEX RANGE SCAN은 주어진 조건절에 따라 인덱스에서 일부 구간만을 읽어오는 방식입니다. 흔히 사용하는 비교 연산자(=, >, <, BETWEEN, LIKE 'abc%')가 있을 때 주로 사용되며, 조건이 인덱스 컬럼에 명확하게 매핑되어 있어야 효과적입니다.

SELECT * FROM employees WHERE department_id BETWEEN 10 AND 20;

이 경우 인덱스가 department_id에 존재하면 해당 범위만 스캔하게 되어 I/O 비용이 적고 빠른 성능을 기대할 수 있습니다.

2. FULL TABLE SCAN – 조건 무시, 테이블 전체 스캔

FULL SCAN은 인덱스를 무시하고 테이블 전체를 차례로 읽는 방식입니다. 일반적으로는 느릴 것이라 생각하지만, 다음과 같은 경우에는 오히려 효율적일 수 있습니다:

  • 조건절이 대부분의 데이터를 포함하는 경우 (예: 전체의 80% 이상)
  • 인덱스가 없는 경우
  • 병렬 처리를 통해 전체 스캔이 더 빠른 경우
  • 통계 정보나 옵티마이저 판단에 의해 인덱스 사용이 비효율적이라고 판단될 경우

예를 들어, 다음과 같은 쿼리는 조건절이 너무 광범위해 인덱스보다 FULL SCAN이 더 나을 수 있습니다.

SELECT * FROM orders WHERE order_date < SYSDATE;

3. 옵티마이저의 판단 기준

오라클 옵티마이저는 다음 요소를 기준으로 INDEX RANGE SCAN과 FULL SCAN 중 하나를 선택합니다.

  • 통계 정보: 테이블과 인덱스에 대한 최신 통계 정보
  • 데이터 분포도: 조건절이 얼마나 많은 행을 포함하는지
  • 인덱스 선택도: 인덱스가 얼마나 고유한 값들을 가지고 있는지
  • 병렬 처리 가능 여부

실제 실행계획에서 두 방식이 교체되는 경우는 의외로 많기 때문에, 반드시 EXPLAIN PLAN 또는 AUTOTRACE 등을 통해 실행계획을 확인하는 것이 중요합니다.

✅ 마무리

INDEX RANGE SCAN과 FULL TABLE SCAN은 단순히 "인덱스가 있으니까 인덱스 쓰자"는 기준으로 판단할 수 없습니다. 실무에서는 통계 정보, 데이터 양, 조건절, 병렬 처리 여부 등 다양한 요인을 종합적으로 고려해 어떤 방식이 더 빠를지 판단해야 하며, 이를 위해 실행계획 분석은 필수입니다.

#오라클 #SQL #실행계획 #성능 #인덱스 #실무팁 #쿼리튜닝

728x90
LIST