인덱스(Index) 란?

데이터베이스에서 데이터 검색을 빠르게 하기 위해 사용되는 데이터 구조이다. 주로 트리 기반의 구조를 사용하지만, 다양한 형태의 인덱스가 있다.

 

B-트리 인덱스

가장 일반적으로 사용되는 인덱스 유형으로, 데이터를 균형있게 유지하며 빠른 검색을 제공한다. 키 값들을 정렬된 순서로 유지하고 각 노드는 여러 자식 노드를 가질 수 있다.

 

B-트리 인덱스는 3가지 유형의 블록으로 이루어져 있는데, 바로 루트 블록, 브랜치 블록, 리프 블록이다.

루트 블록은 트리의 시작점이자 최상단에 위치하는 단 하나의 블록이다.

리프 블록은 최하단에 위치하며 실제 데이터 또는 데이터에 대한 포인터를 보유하고 있다.

마지막으로 브랜치 블록은 루트 블록과 리프 블록 사이에 위치한 블록들이며, 블록들을 연결하고 검색 경로를 제공하는 것이 주된 역할이다. 각 브랜치 블록은 여러 키를 포함하고 각 키들은 각각 다른 하위 블록들을 가리키는 포인터와 연결된다.

 

 

 

SQL Server의 클러스터형 인덱스

클러스터형 인덱스는 테이블의 물리적인 저장 순서를 인덱스의 키 값 순서대로 정렬하는 인덱스이다. 이로 인해 클러스터형 인덱스를 사용하는 테이블에서는 키 값에 따라 데이터 검색이 매우 빠르게 이루어질 수 있다.

 

SQL Server의 인덱스 종류는 저장 구조에 따라 클러스터형(clustered) 인덱스와 비클러스터형(nonclusterd) 인덱스로 나뉜다. 우리가 알아볼 것은 이 중 클러스터형 인덱스이다.

클러스터형 인덱스는 데이터를 키 값의 물리적 순서로 저장하기 때문에, 테이블 당 하나의 클러스터형 인덱스만 생성할 수 있다. 검색 속도가 매우 빠르며, 특히 범위 검색에 유리하다는 장점이 있지만, 데이터 삽입, 삭제, 갱신 작업이 비클러스터형 인덱스에 비해 느릴 수 있다는 단점이 있다.

'DataBase > SQLD' 카테고리의 다른 글

테이블 조인(Join) 기법 및 수행 원리  (1) 2024.04.28
옵티마이저(Optimizer)  (1) 2024.04.28
절차형 SQL  (0) 2024.04.27
윈도우 함수(WINDOW 함수)  (2) 2024.04.26
그룹함수(Group Function)  (0) 2024.04.26

테이블에서 조인(Join) 이란?

두 개 이상의 테이블을 하나의 집합으로 만드는 연산이다. SQL문에서 FROM 절에 두 개 이상의 테이블이 나열될 경우 조인이 수행된다. 조인 연산은 두 테이블 사이에서 수행된다. FROM 절에 세 테이블 이상이 존재한다고 해도, 두 개씩 순차적으로 묶어서 조인이 수행될 것이다. 이때 조인 기법은 두 개의 테이블을 조인할 때 사용할 수 있는 방법이다.

 

NL 조인(Join)

Nested Loops 조인의 약어이며, 한 테이블의 각 행에 대해 다른 테이블의 모든 행을 검색하여 일치하는 행을 찾습니다. 이 방식은 한 쪽 테이블이 작고 다른 쪽 테이블이 크거나, 적절한 인덱스가 있는 경우 효율적이다. 특히 NL Join은 랜덤 방식으로 데이터를 액세스하기 때문에 처리 범위가 좁은 것이 유리하다. 일반적으로 선행 테이블(Outer Table)과 후행 테이블(Inner Table)로 나뉘어서 조작됩니다. 이 구조는 각 선행 테이블의 행에 대해 후행 테이블의 모든 행을 반복적으로 검색하는 방식으로 동작합니다. 보통 선행 테이블로 상대적으로 작은 테이블을 선택한다.

 

 

Sort Merge 조인(Join)

소트 머지 조인은 두 테이블의 조인 컬럼을 기준으로 각각 정렬한 다음, 두 테이블을 병합하면서 조인 조건에 맞는 행을 찾는다. 이 조인 방식은 두 테이블의 크기가 비슷하고 이미 정렬되어 있거나 정렬 비용이 적을 때 유리하다.

 

Sort Merge Join은 랜덤 엑세스로 NL Join에서 부담이 되던 넓은 범위의 데이터를 처리할 때 이용되던 조인 기법이다. 그러나 Sort Merge Join은 정렬할 데이터가 많아 메모리에서 모든 정렬 작업을 수행하기 어려운 경우에는 임시 영역(디스크)을 사용하기 때문에 성능이 떨어질 수 있다.

 

일반적으로 대량의 조인 작업에서 정렬 작업을 필요로 하는 Sort Merge Join보다는 CPU 작업 위주로 처리하는 Hash Join이 성능상 유리하다. 그러나 Sort Merge Join 은 Hash Join 과는 달리 동등 조인 뿐만 아니라 비동등 조인에 대해서도 조인 작업이 가능하다는 장점이 있다.

 

마지막으로, Sort Merge Join은 조인 칼럼의 인덱스를 사용하지 않기 때문에 조인 칼럼의 인덱스가 존재하지 않을 경우에도 사용할 수 있는 조인 기법이다.

 

 

 

Hash 조인(Join)

해시 조인은 먼저 조인할 테이블의 조인 컬럼을 기준으로 해시 테이블을 만들고, 다른 테이블의 조인 컬럼에 대한 해시를 계산하여 해시 테이블과 비교합니다. 이는 대량의 데이터를 빠르게 조인할 수 있게 해 줍니다. 특히, 메모리 내에서 해시 테이블을 완전히 구성할 수 있을 정도로 충분한 메모리가 있는 경우에 매우 빠른 성능을 보인다.

 

Hash Join은 조인 칼럼의 인덱스를 사용하지 않기 때문에 조인 칼럼의 인덱스가 존재하지 않을 경우에도 사용할 수 있는 조인 기법이다. Hash Join은 해쉬 함수를 이용하여 조인을 수행하기 때문에 '=' 로 수행하는 조인, 즉, 동등 조인에서만 사용할 수 있다. 해쉬 함수를 적용한 값은 어떤 값으로 해슁될 지 알 수 없다. 해쉬 함수가 적용될 때 동일한 값은 항상 같은 값으로 해슁됨이 보장된다. 그러나 해쉬 함수를 적용할 때 보다 큰 값이 항상 큰 값으로 해슁되고 작은 값이 항상 작은 값으로 해슁된다는 보장은 없다. 그렇기 때문에 Hash Join은 동등 조인(=)에서만 사용할 수 있다.

 

Hash Join은 조인 작업을 수행하기 위해 해쉬 테이블을 메모리에 생성해야 한다. 생성된 해쉬 테이블의 크기가 메모리에 적재할 수 있는 크기보다 더 커지면 임시 영역(디스크)에 해쉬 테이블을 저장한다. 그러면 추가적인 작업이 필요해 진다. 그렇기 때문에 Hash Join 을 할 때는 결과 행의 수가 적은 테이블을 선행 테이블로 사용하는 것이 좋다. 선행 테이블의 결과를 완전히 메모리에 저장할 수 있다면 임시 영역에 저장하는 작업이 발생하지 않기 때문이다.

 

Hash Join에서는 선행 테이블을 이용하여 먼저 해쉬 테이블을 생성한다고 해서 선행 테이블을 Build Input 이라고도 하며, 후행 테이블은 만들어진 해쉬 테이블에 대해 해쉬 값의 존재여부를 검사한다고 Prove Input 해서 이라고도 한다

'DataBase > SQLD' 카테고리의 다른 글

인덱스(Index)  (0) 2024.04.28
옵티마이저(Optimizer)  (1) 2024.04.28
절차형 SQL  (0) 2024.04.27
윈도우 함수(WINDOW 함수)  (2) 2024.04.26
그룹함수(Group Function)  (0) 2024.04.26

옵티마이저(Optimizer) 란?

옵티마이저(Optimizer)는 데이터베이스 관리 시스템(DBMS)에서 매우 중요한 구성 요소로, 사용자가 제출한 SQL 쿼리를 가장 효율적인 방식으로 실행하기 위한 최적의 실행 계획을 결정하는 역할을 한다. 옵티마이저의 목표는 데이터베이스 시스템의 자원을 최대한 효율적으로 사용하여 쿼리의 실행 시간을 최소화하고, 시스템의 전반적인 성능을 향상시키는 것이다.

 

 

옵티마이저의 주요 기능

쿼리 분석

옵티마이저는 먼저 SQL 쿼리를 분석하여 이해한다. 이 과정에서 쿼리가 사용하는 테이블, 조인, 필터 등을 식별한다.

 

통계 수집

옵티마이저는 데이터베이스의 통계 정보를 수집하고 활용한다. 이 통계 정보에는 테이블 크기, 인덱스 정보, 칼럼의 데이터 분포, 카디널리티(특정 필드의 고유값의 수) 등이 포함된다. 이 정보는 쿼리 실행에 영향을 미칠 수 있는 중요한 요소이다.

 

실행 계획 생성

통계 정보와 쿼리 분석 결과를 기반으로, 옵티마이저는 여러 가능한 실행 경로를 고려한다. 예를 들어, 어떤 테이블을 먼저 스캔할 것인지, 어떤 인덱스를 사용할 것인지, 조인은 어떤 방식으로 처리할 것인지 등을 결정한다.

 

비용 평가

각 실행 계획에 대해 '비용'을 추정한다. 비용은 쿼리를 실행하는 데 필요한 I/O, CPU 사용량, 메모리 사용량 등을 포함한다. 옵티마이저는 이 비용을 최소화하는 실행 계획을 선택한다.


실행 계획 선택

최종적으로 가장 비용이 낮은 것으로 판단되는 실행 계획을 선택하여 실행한다.

 

 

 

옵티마이저의 종류

 

1. 규칙 기반 옵티마이저(Rule-based Optimizer, RBO)

 

규칙 기반 옵티마이저는 이름 그대로 규칙(우선 순위)을 가지고 실행계획을 생성한다. 실행계획을 생성하는 규칙을 이해하면 누구나 실행계획을 비교적 쉽게 예측할 수 있다. 규칙기반 옵티마이저가 실행계획을 생성할 때 참조하는 정보에는 SQL문을 실행하기 위해서 이용 가능한 인덱스 유무와 (유일, 비유일, 단일, 복합 인덱스)종류, SQL문에서 사용하는 연산자(=, <, <>, LIKE, BETWEEN 등)의 종류 그리고 SQL문에서 참조하는 객체(힙 테이블, 클러스터 테이블 등)의 종류 등이 있다. 이러한 정보에 따라 우선 순위(규칙)가 정해져 있고, 이 우선 순위를 기반으로 실행계획을 생성한다. 결과적으로 규칙기반 옵티마이저는 우선 순위가 높은 규칙이 적은 일량으로 해당 작업을 수행하는 방법이라고 판단하는 것이다.

 

다음은 규칙 기반 옵티마이저의 15가지 규칙이다. 순위의 숫자가 낮을 수록 높은 우선순위를 가진다.

순위 액세스 기법 설명
1 Single row by rowid ROWID를 통해서 테이블에서 하나의 행을 액세스하는 방식
2 Single row by cluster join  
3 Single row by hash cluster key with unique or primary key  
4 Single row by unique or primary key 유일 인덱스(Unique Index)를 통해서 하나의 행을 액세스하는 방식
5 Cluster join  
6 Hash cluster key  
7 Indexed cluster key  
8 Composite index 복합 인덱스동등(`=` 연산자)조건으로 검색하는 경우 (이때 복합 인덱스란, 두 개 이상의 칼럼을 포함하는 데이터베이스 인덱스이다.)
9 Single column index 단일 컬럼 인덱스동등(`=` 연산자)조건으로 검색하는 경우
10 Bounded range search on indexed columns 인덱스가 생성되어 있는 컬럼에 양쪽 범위를 한정하는 형태로 검색하는 경우 (예를 들어, 이러한 연산자에는 BETWEEN, LIKE 등이 있다.)
11 Unbounded range search on indexed columns 인덱스가 생성되어 있는 컬럼에 한쪽 범위만 한정하는 형태로 검색하는 방식 (예를 들어, 이러한 연산자에는 >, >=, <, <= 등이 있다.)
12 Sort merge join  
13 MAX or MIN of indexed column  
14 ORDER BY on indexed column  
15 Full table scan 전체 테이블을 액세스하면서 조건절에 주어진 조건을 만족하는 행만을 추출

 

 


2. 비용 기반 옵티마이저(Cost-based Optimizer, CBO)

 

현대 데이터베이스에서 널리 사용되며, 데이터의 실제 통계를 기반으로 쿼리의 비용을 계산하고 가장 효율적인 실행 계획을 선택한다. 규칙기반 옵티마이저는 조건절에서 ‘=’ 연산자와 'BETWEEN' 연산자가 사용되면 규칙에 따라 ‘=’ 칼럼의 인덱스를 사용하는 것이 보다 적은 일량, 즉, 보다 적은 처리 범위로 작업을 할 것이라고 판단한다. 그러나 실제로는 ‘BETWEEN’ 칼럼을 사용한 인덱스가 보다 일량이 적을 수 있다. 단순한 몇 개의 규칙만으로 현실의 모든 사항을 정확히 예측할 수는 없다. 비용기반 옵티마이저는 이러한 규칙기반 옵티마이저의 단점을 극복하기 위해서 출현하였다.

 

비용기반 옵티마이저는 SQL문을 처리하는데 필요한 비용이 가장 적은 실행계획을 선택하는 방식이다. 여기서 비용이란 SQL문을 처리하기 위해 예상되는 소요시간 또는 자원 사용량을 의미한다. 비용기반 옵티마이저는 비용을 예측하기 위해서 규칙기반 옵티마이저가 사용하지 않는 테이블, 인덱스, 칼럼 등의 다양한 객체 통계정보와 시스템 통계정보 등을 이용한다. 통계정보가 없는 경우 비용기반 옵티마이저는 정확한 비용 예측이 불가능해져서 비효율적인 실행계획을 생성할 수 있다. 그렇기 때문에 정확한 통계정보를 유지하는 것은 비용기반 최적화에서 중요한 요소이다.

 

 

다음은 비용 기반 옵티마이저의 구성요소이다.

구성요소 명 설명
질의 변환기 
(Query Transformer)
SQL 쿼리를 분석하고, 구문적으로 올바른 형태로 변환한다. 또한, 쿼리를 더 효율적으로 실행할 수 있도록 변환하는 여러 최적화를 수행할 수 있다. 예를 들어, 복잡한 쿼리를 간단한 형태로 재작성하거나, 불필요한 조건을 제거하는 등의 작업을 포함할 수 있다. (예를 들어, 서브쿼리를 조인으로 변환, OR 조건을 UNION으로 재작성, 상수 표현식 계산 등)

< 쿼리 파서 및 분석기 >
파싱 엔진: SQL 쿼리를 구문 분석하고 초기 구조를 이해
최적화 엔진: SQL 쿼리를 바탕으로 실행 계획을 생성하고 최적화
대안 계획 생성기 
(Plan Alternatives Generator)
질의 변환기에서 전달된 쿼리에 대해 실행 가능한 여러 가지 실행 계획을 생성

< 실행 계획 생성기 >
조인 전략 결정: 조인의 순서와 방법(네스티드 루프, 해시 조인 등)을 결정
인덱스 선택: 각 쿼리에 대해 사용할 인덱스를 결정
접근 방법 결정: 테이블 전체 스캔 대비 인덱스 스캔 등의 접근 방식 선택

< 최적의 실행 계획 선택기 >
비용 비교: 각 실행 계획의 총 비용을 비교
계획 선택: 가장 비용이 낮은 실행 계획을 선택하여 실행
비용 예측기 
(Cost Estimator)
각 실행 계획의 비용을 추정

< 비용 추정기 예시 >
디스크 I/O 비용: 디스크로부터 데이터를 읽고 쓰는 비용 추정
CPU 비용: 쿼리 처리에 필요한 CPU 시간 추정
네트워크 비용: 데이터 전송에 필요한 비용 추정
메모리 비용: 데이터 처리를 위한 메모리 사용량 추정
딕셔너리 
(Dictionary)
데이터베이스의 메타데이터를 저장하고 관리하는 구성 요소. 주요 통계 정보를 포함하며 쿼리의 파싱, 최적화, 실행 계획의 비용 추정 등에 필수적으로 사용된다.

< 통계 정보의 종류 예시 >
테이블 구조, 테이블 크기(테이블에 저장된 행의 수 등),
인덱스 정보(인덱스의 크기, 개수, 유형),
데이터 분포(칼럼 값의 히스토그램, 유니크한 값의 수),
카디널리티(특정 칼럼 또는 칼럼 조합에서의 유니크한 값의 수)

 

 

 

 

실행 계획(Execution Plan)

실행 계획이란 SQL에서 요구한 사항을 처리하기 위한 절차와 방법을 의미한다. 실행계획을 생성한다는 것은 SQL을 어떤 순서로 어떻게 실행할 지를 결정하는 작업이다. 동일한 SQL에 대해 결과를 낼 수 있는 다양한 처리 방법(실행계획)이 존재할 수 있지만 각 처리 방법마다 실행 시간(성능)은 서로 다를 수 있다. 옵티마이저는 다양한 처리 방법들 중에서 가장 효율적인 방법을 찾아준다. 즉, 옵티마이저는 최적의 실행계획을 생성해 준다.

 

예를 들어, Oracle의 실행계획을 구성하는 요소는 다음과 같다.

 

 

  1. 조인 기법(Join Method)
    - 두 개의 테이블을 조인할 때 사용할 수 있는 방법
    - ex. )) NL Join, Hash Join, Sort Merge Join 등


  2. 액세스 기법(Access Method)
    - 하나의 테이블을 액세스할 때 사용할 수 있는 방법
    - ex. )) 인덱스를 이용하여 테이블을 액세스하는 인덱스 스캔(Index Scan)
    - ex. )) 테이블 전체를 모두 읽으면서 조건을 만족하는 행을 찾는 전체 테이블 스캔(Full Table Scan)


  3. 최적화 정보(Optimization Information)
    - 옵티마이저가 실행계획의 각 단계마다 예상되는 비용 사항을 표시한 것이다.
    - 실행계획에 비용 사항이 표시된다는 것은 비용기반 최적화 방식으로 실행계획을 생성했다는 것

    최적화 정보에는 Cost, Card, Bytes 가 있다.
    - Cost : 상대적인 비용 정보
    - Card : Cardinality의 약자로서 주어진 조건을 만족한 결과 집합의 건수
    - Bytes : 결과 집합이 차지하는 메모리 양

    이러한 비용 정보는 실제로 SQL을 실행하고 얻은 결과가 아니라 통계 정보를 바탕으로 옵티마이저가 계산한 예상치이다. 만약 이러한 비용 사항이 실행계획에 표시되지 않았다면 이것은 규칙기반 최적화 방식으로 실행계획을 생성한 것이다.


  4. 연산(Operation)
    - 여러 가지 조작을 통해서 원하는 결과를 얻어내는 일련의 작업
    - 연산에는 조인 기법(NL Join, Hash Join, Sort Merge Join), 액세스 기법(인덱스 스캔, 전체 테이블 스캔 등), 필터, 정렬, 집계, 뷰 등 다양한 종류가 존재한다. 예를 들어, SQL 정렬을 목적으로 ORDER BY 를 수행했다면 정렬 연산이 표시된다.

'DataBase > SQLD' 카테고리의 다른 글

인덱스(Index)  (0) 2024.04.28
테이블 조인(Join) 기법 및 수행 원리  (1) 2024.04.28
절차형 SQL  (0) 2024.04.27
윈도우 함수(WINDOW 함수)  (2) 2024.04.26
그룹함수(Group Function)  (0) 2024.04.26

절차형 SQL 이란?

표준 SQL의 확장으로, 프로그래밍에서 볼 수 있는 제어 구조를 사용하여 더욱 복잡하고 상세한 데이터 처리를 할 수 있게 해주는 SQL의 형태이다. 절차형 SQL은 데이터베이스에서 로직을 구현할 때 사용되며, 일반적인 SQL 명령어로는 처리하기 어려운 조건부 로직, 반복, 변수 사용 등을 가능하게 한다.

일반 SQL이 선언적(declarative) 언어라면, 절차형 SQL은 명령형(imperative) 특성을 가지고 있다. 즉, 데이터를 어떻게 가져올지만을 명시하는 대신, 어떤 절차를 따라 데이터를 처리할지를 상세하게 기술할 수 있다.

 

다음은 다양한 데이터베이스에서 절차형SQL을 지원하는 제품 목록이다.

  • Oracle의 PL/SQL (Procedural Language/SQL)
  • Microsoft SQL Server의 Transact-SQL (T-SQL)
  • PostgreSQL의 PL/pgSQL
  • IBM DB2의 SQL PL
  • MySQL의 SQL/PSM (Persistent Stored Modules)

 

절차적 언어, 선언적 언어랑 구체적으로 어떻게 다른건데?

선언적 언어는 "무엇을(What)" 할지에 초점을 맞추고, 절차적 언어는 "어떻게(How)" 할지에 초점을 맞춘다. 선언적 언어는 개발자로 하여금 내부 메커니즘에서 벗어나 결과에만 집중할 수 있게 해주는 반면, 절차적 언어는 개발자가 알고리즘의 각 단계를 직접 제어할 수 있게 해준다.

 

얼핏보면 다음 일반적인 SQL 문장도 구체적으로 뭘 할지 지정해준 것처럼 보인다.

SELECT 이름, 이메일 FROM 고객;

 

그러나 그렇지 않다.

 

위 SQL 문에는 데이터베이스에 '무엇을' 해야 하는지를 요청하고 있다. 즉, '이름'과 '이메일'을 '고객' 테이블에서 선택하라고 요청하고 있지만, 이 과정에서 데이터 접근 방식이나, 쿼리를 최적화하는 방법, 실제 데이터를 어떻게 디스크에서 메모리로 로딩하는지, 또는 병렬 처리가 가능한 경우 어떻게 처리될지 등은 명시되어 있지않다. 사용자가 신경 쓸 필요 없이 데이터베이스 관리 시스템이 알아서 처리하고 있다.


반면, 절차적 언어에서는 특정 작업을 수행하기 위해 필요한 모든 단계를 명시적으로 기술해야 한다. 예를 들어, 대표적인 절차적 프로그래밍 언어인 C를 사용해 배열에서 최대값을 찾는 경우, 개발자는 초기 최대값 설정하고 배열의 각 요소를 순회하며, 현재 요소가 기존의 최대값보다 큰지 비교하거나 조건에 따라 최대값 업데이트하는 일들을 직접 명시해주어야 한다.

 

 

 

PL/SQL 란?

Procedural Language extensions to SQL 의 약자로, 오라클 데이터베이스에서 사용하는 절차적 프로그래밍 언어이다.

 

주요 특징은 다음과 같다.

 

블록 구조

PL/SQL 코드는 선언부, 실행부, 예외 처리부로 구성되는 블록 구조를 가진다. 각 블록은 특정 작업을 수행하고, 블록 내에서 변수를 선언하고, 조건문과 루프를 사용하여 로직을 구현하는 등 기능별로 모듈화가 가능하다.


SQL 통합

PL/SQL은 SQL 명령어를 자연스럽게 통합하여 사용한다. 이를 통해 데이터베이스에 저장된 데이터를 처리하는 SQL 문장을 프로그램 로직 내에서 직접 호출하고, 결과를 변수에 저장하며, 데이터를 수정할 수 있다. 즉, 변수, 상수 등을 선언하여 SQL 문장 간 값을 교환할 수도 있는 것이다.


절차적 기능

조건문(IF), 반복문(LOOP), 함수, 프로시저 등 절차적 언어를 사용하여 절차적인 프로그래밍의 기능을 제공한다. 이를 통해 복잡한 비즈니스 로직을 구현할 수 있다.


트리거

데이터베이스 이벤트(예: 데이터 삽입, 수정, 삭제)에 반응하여 자동으로 실행되는 PL/SQL 코드를 작성할 수 있다. 이는 데이터 무결성을 유지하고, 필요한 작업을 자동화하는 데 유용하다.


예외 처리

DBMS 정의 에러나 사용자 정의 에러를 정의하여 사용할 수 있다.

 

 

PL/SQL 사용방법 (기본 문법)

DECLARE
  -- 선언부
  v_number NUMBER := 10;
BEGIN
  -- 실행부
  v_number := v_number + 20;
  DBMS_OUTPUT.PUT_LINE('Updated Number: ' || v_number);
EXCEPTION
  -- 예외 처리부
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
  • 선언부(Declaration Section)
    DECLARE 블록이다.
    변수, 상수, 타입, 커서 등을 선언한다.
    선택적으로 작성할 수도 있고 안할 수도 있다.

  • 실행부(Execution Section)
    BEGIN ~ END 블록이다.
    실제 실행할 SQL 문과 PL/SQL 명령어가 포함된다.
    필수로 작성해야 하는 부분이다.

  • 예외 처리부(Exception Handling Section)
    EXCEPTION 블록이다.
    예외 처리 로직이 포함된다.
    선택적으로 작성할 수도 있고 안할 수도 있다.

 

'DataBase > SQLD' 카테고리의 다른 글

테이블 조인(Join) 기법 및 수행 원리  (1) 2024.04.28
옵티마이저(Optimizer)  (1) 2024.04.28
윈도우 함수(WINDOW 함수)  (2) 2024.04.26
그룹함수(Group Function)  (0) 2024.04.26
서브쿼리(Subquery)  (2) 2024.04.26

윈도우 함수(WINDOW 함수) 란?

윈도우 함수는 SQL에서 특정 데이터셋의 '윈도우'나 '프레임'에 대해 집계, 순위 및 분석 작업을 수행할 수 있는 강력한 도구이다. 이 함수들은 일반 집계 함수와 비슷하지만, 결과를 그룹화하지 않고 원본 데이터의 구조를 유지하면서 각 행에 대한 계산 결과를 반환할 수 있다는 차이점이 있다. 윈도우 함수는 주로 데이터의 특정 순위를 정하거나, 이동 평균을 계산하거나, 각 그룹 내에서의 행의 위치를 결정하는 등의 작업에 사용된다. 분석 함수 (ANALYTIC FUNCTION) 나 순위 함수 (RANK FUNCTION) 로도 알려져 있는 윈도우 함수는 데이터웨어하우스에서 발전한 기능이다.

복잡하거나 자원을 많이 사용하는 튜닝 기법들을 대체할 수 있는 DBMS의 새로운 기능은 튜닝 관점에서도 최적화된 방법이므로 적극적으로 활용할 필요가 있다. 같은 결과가 나오는 변형된 튜닝 문장보다는 DBMS 벤더에서 최적화된 자원을 사용하도록 만들어진 새로운 기능을 사용하는 것이 일반적으로 더욱 효과가 좋기 때문이다.

WINDOW 함수는 기존에 사용하던 집계 함수도 있고, 새로이 WINDOW 함수 전용으로 만들어진 기능도 있다. 그리고 WINDOW 함수는 다른 함수와는 달리 중첩(NEST)해서 사용하지는 못하지만 서브쿼리에서는 사용할 수 있다.

 

 

윈도우 함수 문법

SELECT WINDOW_FUNCTION (ARGUMENTS) OVER ( 
    [PARTITION BY column1, column2, ...] 
    [ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...]
    [WINDOWING 절]
)
FROM TABLE;

 

WINDOWING 절

  • 함수의 대상이 되는 행 기준의 범위를 강력하게 지정할 수 있다.
  • 주로 ROWS 또는 RANGE 키워드를 사용하여 지정하며, 파티션 내의 데이터에 대해 어떻게 창(window)을 설정할지 정의한다.
  • ROWS는 물리적인 결과 행의 수를, RANGE는 논리적인 값에 의한 범위를 나타내는데, 둘 중의 하나를 선택해서 사용할 수 있다.
  • 다만, WINDOWING 절은 SQL Server에서는 지원하지 않는다.

 

 

 

RANK 함수

  • ORDER BY 를 포함한 쿼리문에서 특정 항목 칼럼 에 대한 순위를 구하는 함수
  • 특정 범위 (PARTITION) 내에서 순위를 구할 수도 있고 전체 데이터에 대한 순위를 구할 수도 있다.
  • 동일한 값에 대해서는 동일한 순위를 부여하게 된다.
SELECT 	JOB, ENAME, SAL,
	RANK() OVER (ORDER BY SAL DESC) ALL_RANK,
	RANK() OVER (PARTITION BY JOB ORDER BY SAL DESC) JOB_RANK
FROM EMP;
JOB		ENAME	SAL	ALL_RANK	JOB_RANK
---		------	---	---------	---------
PRESIDENT 	KING 	5000 	1 		1
ANALYST 	FORD 	3000 	2 		1
ANALYST 	SCOTT 	3000 	2 		1
MANAGER 	JONES 	2975 	4 		1
MANAGER 	BLAKE 	2850 	5 		2
MANAGER 	CLARK 	2450 	6 		3
SALESMAN 	ALLEN 	1600 	7 		1
SALESMAN 	TURNER 	1500 	8 		2
CLERK 		MILLER 	1300 	9 		1
SALESMAN 	WARD 	1250 	10 		3
SALESMAN 	MARTIN 	1250 	10 		3
CLERK 		ADAMS 	1100 	12 		2
CLERK 		JAMES 	950 	13 		3
CLERK 		SMITH 	800 	14 		4

 

 

 

DENSE_RANK 함수

  • RANK 함수와 같지만, 차이점은 동일한 등수가 나온만큼 카운트를 더하지 않고 연속적인 순위를 배정한다.
SELECT 	JOB, ENAME, SAL,
	RANK() OVER (ORDER BY SAL DESC) RANK,
	DENSE_RANK() OVER (ORDER BY SAL DESC) DENSE_RANK
FROM EMP;
JOB		ENAME	SAL	RANK 	DENSE_RANK
---		------ 	--- 	----- 	-----------
PRESIDENT 	KING 	5000 	1 	1
ANALYST 	FORD 	3000 	2 	2
ANALYST 	SCOTT 	3000 	2 	2
MANAGER 	JONES 	2975 	4 	3
MANAGER 	BLAKE 	2850 	5 	4
MANAGER 	CLARK 	2450 	6 	5
SALESMAN 	ALLEN 	1600 	7 	6
SALESMAN 	TURNER 	1500 	8 	7
CLERK 		MILLER 	1300 	9 	8
SALESMAN 	WARD 	1250 	10 	9
SALESMAN 	MARTIN 	1250 	10 	9
CLERK 		ADAMS 	1100 	12 	10
CLERK 		JAMES 	950 	13 	11
CLERK 		SMITH 	800 	14 	12

 

 

 

ROW_NUMBER 함수

  • RANK나 DENSE_RANK 함수가 동일한 값에 대해서는 동일한 순위를 부여하는데 반해, 동일한 값이라도 고유한 순위를 연속적으로 부여한다.
SELECT 	JOB, ENAME, SAL,
	RANK() OVER (ORDER BY SAL DESC) RANK,
	ROW_NUMBER() OVER (ORDER BY SAL DESC) ROW_NUMBER
FROM EMP;
JOB		ENAME	SAL	RANK	ROW_NUMBER
---		------	---	-----	-----------
PRESIDENT 	KING 	5000 	1 	1
ANALYST 	FORD 	3000 	2 	2
ANALYST 	SCOTT 	3000 	2 	3
MANAGER 	JONES 	2975 	4 	4
MANAGER 	BLAKE 	2850 	5 	5
MANAGER 	CLARK 	2450 	6 	6
SALESMAN 	ALLEN 	1600 	7 	7
SALESMAN 	TURNER 	1500 	8 	8
CLERK 		MILLER 	1300 	9 	9
SALESMAN 	WARD 	1250 	10 	10
SALESMAN 	MARTIN 	1250 	10 	11
CLERK 		ADAMS 	1100 	12 	12
CLERK 		JAMES 	950 	13 	13
CLERK 		SMITH 	800 	14 	14

 

 

 

SUM 함수

예제 - 1

SELECT 	MGR, ENAME, SAL, 
	SUM(SAL) OVER (PARTITION BY MGR) MGR_SUM
FROM EMP;
MGR	ENAME	SAL	MGR_SUM
----	------	---	---------
7566 	FORD 	3000 	6000
7566 	SCOTT 	3000 	6000
7698 	JAMES 	950 	6550
7698 	ALLEN 	1600 	6550
7698 	WARD 	1250 	6550
7698 	TURNER 	1500 	6550
7698 	MARTIN 	1250 	6550
7782 	MILLER 	1300 	1300
7788 	ADAMS 	1100 	1100
7839 	BLAKE 	2850 	8275
7839 	JONES 	2975 	8275
7839 	CLARK 	2450 	8275
7902 	SMITH 	800 	800
	KING 	5000 	5000

 

 

예제 - 1

SELECT 	MGR, ENAME, SAL,
	SUM(SAL) OVER (
    		PARTITION BY MGR ORDER BY SAL RANGE UNBOUNDED PRECEDING
	) as MGR_SUM
FROM EMP

RANGE UNBOUNDED PRECEDING

현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다. 현재 행에서 지정된 방향(여기서는 시작부터 현재 행까지)으로 데이터의 범위를 지정하는 데 사용되는데, 이 구문을 사용하면 현재 행을 포함하여 그 이전의 모든 행을 계산 범위로 포함한다.

 

RANGE UNBOUNDED PRECEDING
정렬 기준의 값이 같은 모든 행을 포함하여 계산한다. 
즉, 동일한 값에 대해 경계가 확장된다.
ROWS UNBOUNDED PRECEDING
물리적인 행의 수를 기준으로 하여 계산한다. 
즉, 동일한 값이어도 상관없이 순서대로 지정된 행만큼만 포함한다.

MGR	ENAME	SAL	MGR_SUM
----	------	---	---------
7566 	SCOTT 	3000 	6000
7566 	FORD 	3000 	6000

7698 	JAMES 	950 	950
7698 	WARD 	1250 	3450
7698 	MARTIN 	1250 	3450
7698 	TURNER 	1500 	4950
7698 	ALLEN 	1600 	6550

7782 	MILLER 	1300 	1300

7788 	ADAMS 	1100 	1100

7839 	CLARK 	2450 	2450
7839 	BLAKE 	2850 	5300
7839 	JONES 	2975 	8275

7902 	SMITH 	800 	800
	KING 	5000 	5000

 

 

 

MAX / MIN 함수

  • 파티션별 윈도우의 최대/최소값을 구할 수 있다.
  • 다음은 INLINE VIEW를 이용해 파티션별 최대값을 가진 행만 추출하는 예제이다.
SELECT MGR, ENAME, SAL
FROM (
	SELECT 	MGR, ENAME, SAL, 
		MAX(SAL) OVER (PARTITION BY MGR) as IV_MAX_SAL
	FROM EMP
    )
WHERE SAL = IV_MAX_SAL ;
MGR	ENAME	SAL
----	------	---
7566 	FORD 	3000
7566 	SCOTT 	3000
7698 	ALLEN 	1600
7782 	MILLER 	1300
7788 	ADAMS 	1100
7839 	JONES 	2975
7902 	SMITH 	800
	KING 	5000

 

 

 

AVG 함수

SELECT 	MGR, ENAME, HIREDATE, SAL,
	ROUND (AVG(SAL) OVER (
    		PARTITION BY MGR ORDER BY HIREDATE
		ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)) as MGR_AVG
FROM EMP;

ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING

현재 행을 기준으로 파티션 내에서 앞의 한 건, 현재 행, 뒤의 한 건을 범위로 지정한다.

MGR	ENAME	HIREDATE	SAL	MGR_AVG
----	------	---------	---	---------
7566 	FORD 	1981-12-03 	3000 	3000
7566 	SCOTT 	1987-07-13 	3000 	3000

7698 	ALLEN 	1981-02-20 	1600 	1425
7698 	WARD 	1981-02-22 	1250 	1450
7698 	TURNER 	1981-09-08 	1500 	1333
7698 	MARTIN 	1981-09-28 	1250 	1233
7698 	JAMES 	1981-12-03 	950 	1100

7782 	MILLER 	1982-01-23 	1300 	1300
7788 	ADAMS 	1987-07-13 	1100 	1100
7839 	JONES 	1981-04-02 	2975 	2913
7839 	BLAKE 	1981-05-01 	2850 	2758
7839 	CLARK 	1981-06-09 	2450 	2650
7902 	SMITH 	1980-12-17 	800 	800
	KING 	1981-11-17 	5000 	5000

 

 

 

COUNT 함수

SELECT 	ENAME, SAL, 
	COUNT(*) OVER (
    		ORDER BY SAL
		RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING) as SIM_CNT
FROM EMP;

RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING

현재 행의 급여값을 기준으로 급여가 -50 에서 +150 의 범위 내에 포함된 모든 행이 대상이 된다.

ENAME	SAL	SIM_CNT	(범위 값)
------	---	---	-------
SMITH 	800 	2 	( 750~ 950)
JAMES 	950 	2 	( 900~1100)
ADAMS 	1100 	3 	(1050~1250)
WARD 	1250 	3 	(1200~1400)
MARTIN 	1250 	3 	(1200~1400)
MILLER 	1300 	3 	(1250~1450)
TURNER 	1500 	2 	(1450~1650)
ALLEN 	1600 	1 	(1550~1750)
CLARK 	2450 	1 	(2400~2600)
BLAKE 	2850 	4 	(2800~3000)
JONES 	2975 	3 	(2925~3125)
SCOTT 	3000 	3 	(2950~3100)
FORD 	3000 	3 	(2950~3100)
KING 	5000 	1 	(4950~5100)

 

 

 

FIRST_VALUE 함수

  • 파티션별 윈도우에서 가장 먼저 나온 값을 구한다.
  • SQL Server 에서는 지원하지 않는 함수이다.
  • MIN 함수를 활용하여 같은 결과를 얻을 수도 있다.
SELECT 	DEPTNO, ENAME, SAL, 
	FIRST_VALUE(ENAME)
	OVER (
    		PARTITION BY DEPTNO ORDER BY SAL DESC
		ROWS UNBOUNDED PRECEDING
        ) as DEPT_RICH
FROM EMP;

ROWS UNBOUNDED PRECEDING

현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다. (현재 행부터 파티션의 시작점까지 모든 행을 참조)

DEPTNO	ENAME	SAL	DEPT_RICH
------	------	---	---------
10 	KING 	5000 	KING
10 	CLARK 	2450 	KING
10 	MILLER 	1300 	KING
20 	SCOTT  	3000 	SCOTT
20 	FORD  	3000 	SCOTT
20 	JONES 	2975 	SCOTT
20 	ADAMS 	1100 	SCOTT
20 	SMITH 	800 	SCOTT
30 	BLAKE 	2850 	BLAKE
30 	ALLEN 	1600 	BLAKE
30 	TURNER 	1500 	BLAKE
30 	MARTIN 	1250 	BLAKE
30 	WARD 	1250 	BLAKE
30 	JAMES 	950 	BLAKE

 

 

 

LAST_VALUE 함수

  • 파티션별 윈도우에서 가장 나중에 나온 값을 구한다.
  • SQL Server 에서는 지원하지 않는 함수이다.
  • MAX 함수를 활용하여 같은 결과를 얻을 수도 있다.
SELECT 	DEPTNO, ENAME, SAL,
	LAST_VALUE(ENAME) OVER (
    		PARTITION BY DEPTNO ORDER BY SAL DESC
		ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as DEPT_POOR
FROM EMP;

ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING

현재 행을 포함해서 파티션 내의 마지막 행까지의 범위를 지정한다.

DEPTNO	ENAME	SAL	DEPT_POOR
------	------	---	----------
10 	KING 	5000 	MILLER
10 	CLARK 	2450 	MILLER
10 	MILLER 	1300 	MILLER
20 	SCOTT 	3000 	SMITH
20 	FORD 	3000 	SMITH
20 	JONES 	2975 	SMITH
20 	ADAMS 	1100 	SMITH
20 	SMITH 	800 	SMITH
30 	BLAKE 	2850 	JAMES
30 	ALLEN 	1600 	JAMES
30 	TURKER 	1500 	JAMES
30 	MARTIN 	1250 	JAMES
30 	WARD 	1250 	JAMES
30 	JAMES 	950 	JAMES

 

 

 

LAG / LEAD함수

  • 파티션별 윈도우에서 이전/이후 몇 번째 행의 값을 가져올 수 있다.
  • SQL Server 에서는 지원하지 않는 함수이다.

예제 - 1

SELECT 	ENAME, HIREDATE, SAL, 
	LAG(SAL) OVER (ORDER BY HIREDATE) as PREV_SAL
FROM EMP
WHERE JOB = 'SALESMAN' ;
ENAME	HIREDATE	SAL	MGR_MIN
-----	--------	---	---------
ALLEN 	1981-02-20 	1600
WARD 	1981-02-22 	1250 	1600
TURNER 	1981-09-08 	1500 	1250
MARTIN 	1981-09-28 	1250 	1500

 

예제 - 2

SELECT 	ENAME, HIREDATE, SAL,
	LAG(SAL, 2, 0) OVER (ORDER BY HIREDATE) as PREV_SAL
FROM EMP
WHERE JOB = 'SALESMAN'

LAG(SAL, 2, 0)

두 행 앞의 SALARY를 가져오고 가져올 값이 없는 경우는 0으로 처리한다.

ENAME	HIREDATE	SAL	PREV_SAL
-----	--------	---	--------
ALLEN 	1981-02-20 	1600 	0
WARD 	1981-02-22 	1250 	0
TURNER 	1981-09-08 	1500 	1600
MARTIN 	1981-09-28 	1250 	1250

 

예제 - 3

SELECT 	ENAME, HIREDATE,
	LEAD (HIREDATE, 1) OVER (ORDER BY HIREDATE) as "NEXTHIRED"
FROM EMP;
ENAME	HIREDATE	NEXTDATE
-----	--------	--------
ALLEN 	1981-02-20 	1981-02-22
WARD 	1981-02-22 	1981-04-02
TURNER 	1981-09-08 	1981-09-28
MARTIN 	1981-09-28

 

 

 

 

< 그룹 내 비율 함수 >

 

RATIO_TO_REPORT 함수

  • 파티션 내 전체 SUM(칼럼)값에 대한 행별 칼럼 값의 백분율을 소수점으로 구할 수 있다.
  • 결과 값은 >0 & <=1 의 범위를 가진다.
  • 그리고 개별 RATIO 의 합을 구하면 1이 된다.
  • SQL Server 에서는 지원하지 않는 함수이다.
SELECT 	ENAME, SAL, 
	ROUND(RATIO_TO_REPORT(SAL) OVER (), 2) as R_R
FROM EMP
WHERE JOB = 'SALESMAN';
ENAME	SAL	R_R
-----	---	----
ALLEN 	1600 	0.29 (1600 / 5600)
WARD 	1250 	0.22 (1250 / 5600)
TURNER 	1250 	0.22 (1250 / 5600)
MARTIN 	1500 	0.27 ( 500 / 5600)

 

 

 

 

PERCENT_RANK 함수

  • 파티션별 윈도우에서 제일 먼저 나오는 것을 0으로, 제일 늦게 나오는 것을 1로 하여, 값이 아닌 행의 순서별 백분율을 구한다.
  • 결과 값은 >=0 & <=1 의 범위를 가진다.
  • SQL Server 에서는 지원하지 않는 함수이다.
SELECT 	DEPTNO, ENAME, SAL,
	PERCENT_RANK() OVER (
    		PARTITION BY DEPTNO ORDER BY SAL DESC
	) as P_R
FROM EMP;
DEPTNO	ENAME	SAL	P_R
------	-----	---	---
10 	KING 	5000 	0
10 	CLARK 	2450 	0.5
10 	MILLER 	1300 	1
20 	SCOTT 	3000 	0
20 	FORD 	3000 	0
20 	JONES 	2975 	0.5
20 	ADAMS 	1100 	0.75
20 	SMITH 	800 	1
30 	BLAKE 	2850 	0
30 	ALLEN 	1600 	0.2
30 	TURKER 	1500 	0.4
30 	MARTIN 	1250 	0.6
30 	WARD 	1250 	0.6
30 	JAMES 	950 	1

 

 

 

 

 

CUME_DIST 함수

  • 파티션별 윈도우의 전체건수에서 현재 행보다 작거나 같은 건 수에 대한 누적백분율을 구한다.
  • 결과 값은 >0 & <=1의 범위를 가진다.
  • SQL Server 에서는 지원하지 않는 함수이다.
SELECT 	DEPTNO, ENAME, SAL,
	CUME_DIST() OVER (
    		PARTITION BY DEPTNO ORDER BY SAL DESC
	) as CUME_DIST
FROM EMP;
DEPTNO	ENAME	SAL	CUME_DIST
------	-----	---	----------
10 	KING 	5000 	0.3333
10 	CLARK 	2450 	0.6667
10 	MILLER 	1300 	1.0000

20 	SCOTT 	3000 	0.4000
20 	FORD 	3000 	0.4000
20 	JONES 	2975 	0.6000
20 	ADAMS 	1100 	0.8000
20 	SMITH 	800 	1.0000

30 	BLAKE 	2850 	0.1667
30 	ALLEN 	1600 	0.3333
30 	TURKER 	1500 	0.5000
30 	MARTIN 	1250 	0.8333
30 	WARD 	1250 	0.8333
30 	JAMES 	950 	1.0000

 

 

 

 

NTILE 함수

  • 파티션별 전체 건수를 ARGUMENT 값으로 N등분한 결과를 구할 수 있다.
SELECT 	ENAME, SAL, 
	NTILE(4) OVER (ORDER BY SAL DESC) as QUAR_TILE
FROM EMP
DEPTNO	ENAME	SAL	QUAR_TILE
------	-----	---	----------
10 	KING 	5000 	1
10 	FORD 	3000 	1
10 	SCOTT 	3000 	1
20 	JONES 	2975 	1

20 	BLAKE 	2850 	2
20 	CLARK 	2450 	2
20 	ALLEN 	1600 	2
20 	TURNER 	1500 	2

30 	MILLER 	1300 	3
30 	WARD 	1250 	3
30 	MARTIN 	1250 	3

30 	ADAMS 	1100 	4
30 	JAMES 	950 	4
30 	SMITH 	800 	4

'DataBase > SQLD' 카테고리의 다른 글

옵티마이저(Optimizer)  (1) 2024.04.28
절차형 SQL  (0) 2024.04.27
그룹함수(Group Function)  (0) 2024.04.26
서브쿼리(Subquery)  (2) 2024.04.26
계층형 질의(Hierarchical Query) - Oracle  (0) 2024.04.26

그룹함수(Group Function) 란?

그룹 함수(집계 함수)는 특정 칼럼의 값들을 그룹화하여 하나의 결과를 반환하는 함수이다. 이들 함수는 주로 여러 행의 데이터에 대한 통계적 계산을 수행할 때 사용되며, GROUP BY 절과 함께 사용되어 여러 행의 그룹별로 결과를 제공한다. 주로 결산 개념의 업무를 가지는 원가나 판매 시스템의 경우에 소계, 중계, 합계, 총 합계 등의 여러 레벨의 결산 보고서를 만드는 업무를 할 때 유용하게 사용된다.

 

 

 

ROLLUP 함수

  • 지정된 컬럼 목록에 대해 계층적인 서브토탈을 생성
  • 일반적으로 주어진 컬럼의 모든 가능한 조합에 대한 서브토탈과 그랜드토탈을 계산하는데 사용
SELECT 	DNAME, JOB,
	COUNT(*) "Total Empl",
	SUM(SAL) "Total Sal"
FROM EMP, DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
GROUP BY DNAME, JOB;
[실행 결과] 
DNAME 		JOB 		Total Empl 	Total Sal
----- 		---- 		-------- 	--------
SALES 		CLERK 		1 		950
SALES 		MANAGER 	1 		2850
SALES 		SALESMAN 	4 		5600
SALES 				6 		9400
RESEARCH 	CLERK 		2 		1900
RESEARCH 	ANALYST 	2 		6000
RESEARCH 	MANAGER 	1 		2975
RESEARCH 			5 		10875
ACCOUNTING 	CLERK 		1 		1300
ACCOUNTING 	MANAGER 	1 		2450
ACCOUNTING 	PRESIDENT 	1 		5000
ACCOUNTING 			3 		8750

 

 

 

GROUPING 함수

  • ROLLUP이나 CUBE에 의한 소계가 계산된 결과에는 GROUPING(EXPR) = 1 이 표시되고, 그 외의 결과에는 GROUPING(EXPR) = 0 이 표시된다.
SELECT 	DNAME, GROUPING(DNAME),
	JOB, GROUPING(JOB),
	COUNT(*) "Total Empl",
	SUM(SAL) "Total Sal"
FROM EMP, DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
GROUP BY ROLLUP (DNAME, JOB);
DNAME 	GROUPING(DNAME) JOB 	GROUPING(JOB) 	Total Empl 	Total Sal
------ 	-------------- 	--- 	----------- 	-------- 	------
SALES 		0 	CLERK 		0 	1 		950
SALES 		0 	MANAGER 	0 	1 		2850
SALES 		0 	SALESMAN 	0 	4 		5600
SALES 		0 			1 	6 		9400
RESEARCH 	0 	CLERK 		0 	2 		1900
RESEARCH 	0 	ANALYST 	0 	2 		6000
RESEARCH 	0 	MANAGER 	0 	1 		2975
RESEARCH 	0 			1 	5 		10875
ACCOUNTING 	0 	CLERK 		0 	1 		1300
ACCOUNTING 	0 	MANAGER 	0 	1 		2450
ACCOUNTING 	0 	PRESIDENT 	0 	1 		5000
ACCOUNTING 	0 			1 	3 		8750
		1 			1 	14 		29025

 

 

 

CUBE 함수

  • ROLLUP에서는 단지 가능한 Subtotal만을 생성하였지만, CUBE는 결합 가능한 모든 값에 대하여 다차원 집계를 생성
  • CUBE를 사용할 경우에는 내부적으로 Grouping Columns의 순서를 바꾸어서 또 한 번의 Query를 추가 수행
  • 뿐만 아니라 Grand Total은 양쪽의 쿼리에서 모두 생성이 되므로 한 번의 쿼리에서는 제거되어야만 하므로 ROLLUP에 비해 시스템의 연산 대상이 많음
SELECT 	CASE GROUPING(DNAME) WHEN 1 THEN 'All Departments' ELSE DNAME END AS DNAME,
	CASE GROUPING(JOB) WHEN 1 THEN 'All Jobs' ELSE JOB END AS JOB,
COUNT(*) "Total Empl",
SUM(SAL) "Total Sal"
FROM EMP, DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
GROUP BY CUBE (DNAME, JOB) ;
DNAME 			JOB Total 	Empl Total 	Sal
------------- 		--------- 	--------- 	--------
All Departments 	All Jobs 	14 		29025
All Departments 	CLERK 		4 		4150
All Departments 	ANALYST 	2 		6000
All Departments 	MANAGER 	3 		8275
All Departments 	SALESMAN 	4 		5600
All Departments 	PRESIDENT 	1 		5000
SALES 			All Jobs 	6 		9400
SALES 			CLERK 		1 		950
SALES 			MANAGER 	1 		2850
SALES 			SALESMAN 	4 		5600
RESEARCH 		All Jobs 	5 		10875
RESEARCH 		CLERK 		2 		1900
RESEARCH 		ANALYST 	2 		6000
RESEARCH 		MANAGER 	1 		2975
ACCOUNTING 		All Jobs 	3 		8750
ACCOUNTING 		CLERK 		1 		1300
ACCOUNTING 		MANAGER 	1 		2450
ACCOUNTING 		PRESIDENT 	1 		5000

 

 

 

 

GROUPING SETS 함수

  • GROUPING SETS는 특정 그룹화 조합만을 명시적으로 지정할 때 사용
  • GROUP BY 문장을 여러 번 반복하지 않아도 원하는 결과를 쉽게 얻을 수 있음.
SELECT 	DECODE(GROUPING(DNAME), 1, 'All Departments', DNAME) AS DNAME,
	DECODE(GROUPING(JOB), 1, 'All Jobs', JOB) AS JOB,
COUNT(*) "Total Empl",
SUM(SAL) "Total Sal"
FROM EMP, DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
GROUP BY GROUPING SETS (DNAME, JOB);
DNAME 		JOB Total 	Empl Total 	Sal
------------ 	--------- 	------- 	------
All Departments CLERK 		4 		4150
All Departments SALESMAN 	4 		5600
All Departments PRESIDENT 	1 		5000
All Departments MANAGER 	3 		8275
All Departments ANALYST 	2 		6000
ACCOUNTING 	All Jobs 	3 		8750
RESEARCH 	All Jobs 	5 		10875
SALES 		All Jobs 	6 		9400

'DataBase > SQLD' 카테고리의 다른 글

절차형 SQL  (0) 2024.04.27
윈도우 함수(WINDOW 함수)  (2) 2024.04.26
서브쿼리(Subquery)  (2) 2024.04.26
계층형 질의(Hierarchical Query) - Oracle  (0) 2024.04.26
분산 데이터베이스의 투명성  (0) 2024.04.23

서브쿼리(Subquery) 란?

서브쿼리(Subquery)란 하나의 SQL 쿼리 내에서 사용되는 다른 SQL 쿼리를 의미한다. 예를 들어 조직(1) 과 사원(M) 테이블을 조인하면 결과는 사원 레벨(M) 의 집합이 생성된다. 그러나 서브쿼리는 서브쿼리 레벨과는 상관없이 항상 메인쿼리 레벨로 결과 집합이 생성된다. 메인쿼리로 조직(1), 서브쿼리로 사원 테이블(M)을 사용하면 결과 집합은 조직(1) 레벨이 된다.

SQL문에서 서브쿼리 방식을 사용해야 할 때 잘못 판단하여 조인 방식을 사용하는 경우가 있다. 예를 들어 결과는 조직 레벨이고 사원 테이블에서 체크해야 할 조건이 존재한다고 가정하자. 이런 상황에서 SQL문을 작성할 때 조인을 사용한다면 결과 집합은 사원 레벨(M)이 될 것이다. 이렇게 되면 원하는 결과가 아니기 때문에 SQL문에 DISTINCT를 추가해서 결과를 다시 조직(1) 레벨로 만든다. 이와 같은 상황에서는 조인 방식이 아니라 서브쿼리 방식을 사용해야 한다. 메인쿼리로 조직을 사용하고 서브쿼리로 사원 테이블을 사용하면 결과 집합은 조직 레벨이 되기 때문에 원하는 결과가 된다.

동작하는 방식에 따른 서브쿼리 분류

1. Un-Correlated(비연관) 서브쿼리

  • Un-Correlated 서브쿼리는 메인 쿼리와 독립적으로 실행되는 서브쿼리
  • 서브쿼리가 메인쿼리 컬럼을 가지고 있지 않은 형태의 서브쿼리
  • 메인 쿼리는 이 서브쿼리의 결과를 사용하여 자신의 연산을 수행한다.
  • 메인쿼리에 값(서브쿼리가 실행된 결과)을 제공하기 위한 목적으로 주로 사용한다.

SELECT 이름, 부서ID
FROM 직원
WHERE 급여 > (
    SELECT AVG(급여)
    FROM 직원
);

 

 

 

2. Correlated(연관) 서브쿼리

  • Correlated 서브쿼리는 메인 쿼리의 각 행과 직접적인 관련이 있는 서브쿼리
  • 서브쿼리가 메인쿼리 컬럼을 가지고 있는 형태의 서브쿼리
  • 일반적으로 메인쿼리가 먼저 수행되어 읽혀진 데이터를 서브쿼리에서 조건이 맞는지 확인하고자 할 때 주로 사용된다.
  • 즉, 메인 쿼리의 각 행마다 서브쿼리가 다시 계산되어 결과를 도출합니다.
SELECT 이름, 부서ID
FROM 직원 e
WHERE 급여 = (
    SELECT MAX(급여)
    FROM 직원
    WHERE 부서ID = e.부서ID
);

 

 

 

반환되는 데이터의 형태에 따른 서브쿼리 분류

1. Single Row(단일 행) 서브쿼리

  • 단일 행 서브쿼리는 단 하나의 행만을 반환하는 서브쿼리
  • 이 서브쿼리는 주로 단일 행 비교 연산자(=, >, <, <=, >=, <>)와 함께 사용
  • 단일 행 서브쿼리는 결과가 반드시 하나의 행과 하나의 컬럼을 반환
SELECT 이름, 부서ID
FROM 직원
WHERE 급여 = (
    SELECT MAX(급여)
    FROM 직원
    WHERE 부서ID = '개발'
);
SELECT PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버
FROM PLAYER
WHERE TEAM_ID = (SELECT TEAM_ID
		FROM PLAYER
		WHERE PLAYER_NAME = '정남일') 
ORDER BY PLAYER_NAME;

 

2. Multi Row(다중 행) 서브쿼리

  • 다중 행 서브쿼리는 하나 이상의 행을 반환할 수 있는 서브쿼리
  • 이 유형의 서브쿼리는 IN, ANY, ALL, EXISTS와 같은 다중 행 비교 연산자와 함께 사용
SELECT 이름, 부서ID
FROM 직원
WHERE 부서ID IN (
    SELECT 부서ID
    FROM 부서
    WHERE 위치 = '서울'
);
SELECT PLAYER_NAME , POSITION , BACK_NO 예제 선수명 포지션 백넘버
FROM PLAYER
WHERE HEIGHT <= (SELECT AVG(HEIGHT)
		FROM PLAYER)
ORDER BY PLAYER_NAME;

 

 

3. Multi Column(다중 컬럼) 서브쿼리

  • 다중칼럼 서브쿼리는 하나 이상의 컬럼을 반환하는 서브쿼리
  • 메인 쿼리와의 비교에 여러 컬럼을 동시에 사용
  • 이러한 서브쿼리는 특히 조인을 대체할 때 유용하게 사용
SELECT 이름, 급여
FROM 직원
WHERE (부서ID, 급여) IN (
    SELECT 부서ID, MAX(급여)
    FROM 직원
    GROUP BY 부서ID
);
SELECT REGION_NAME 연고지명, TEAM_NAME 팀명, E_TEAM_NAME 영문팀명
FROM TEAM
WHERE TEAM_ID IN (SELECT TEAM_ID
		FROM PLAYER
		WHERE PLAYER_NAME = '정현수') 
ORDER BY TEAM_NAME;

 

 

 

그 외 서브쿼리

1. 스칼라 서브쿼리

  • 정확히 하나의 행과 하나의 컬럼을 반환하는 서브쿼리
  • SELECT 문의 SELECT 리스트 내부 또는 WHERE 조건에서 단일 값을 제공하는데 사용
  • 스칼라 서브쿼리는 하나의 값을 반환하므로 메인 쿼리의 각 행마다 연산을 수행

2. 인라인 뷰 (Inline View)

  • SELECT 문 내에서 FROM 절에 정의되는 서브쿼리
  • 일시적인 테이블처럼 사용
  • 복잡한 쿼리를 단순화하거나 재사용을 피할 수 있으며, 계산된 테이블을 바탕으로 추가적인 선택, 조인, 필터링을 수행

3. Top-N 서브쿼리

  • 특정 기준에 따라 상위 N개의 결과만을 반환하는 서브쿼리
  • 일반적으로 정렬(ORDER BY)와 함께 행 제한(LIMIT, FETCH FIRST, ROWNUM)을 사용하여 구현
SELECT 이름, 급여
FROM (
    SELECT 이름, 급여
    FROM 직원
    ORDER BY 급여 DESC
    FETCH FIRST 10 ROWS ONLY
) AS TopSalaries;

 

'DataBase > SQLD' 카테고리의 다른 글

윈도우 함수(WINDOW 함수)  (2) 2024.04.26
그룹함수(Group Function)  (0) 2024.04.26
계층형 질의(Hierarchical Query) - Oracle  (0) 2024.04.26
분산 데이터베이스의 투명성  (0) 2024.04.23
정규화(Normalization)  (0) 2024.04.23

계층형 질의(Hierarchical Query)란?

데이터베이스에서 트리 또는 계층적 구조로 조직화된 데이터를 조회하는 SQL 질의이다. 이런 유형의 질의는 부모-자식 관계를 갖는 데이터를 처리할 때 특히 유용하며, 주로 조직 구조, 제품 카테고리, 파일 시스템 등 계층적으로 조직된 데이터를 다루는 데 적합하다.

Oracle 계층형 질의

SELECT 컬럼1, 컬럼2, ...
FROM 테이블
START WITH 조건
CONNECT BY [NOCYCLE] PRIOR 자식/부모컬럼 = 부모/자식컬럼;
[ORDER SIBLINGS BY 컬럼1, 컬럼2, ...]

START WITH

  • 계층 구조 전개의 시작 위치를 지정하는 구문이다. 즉, 루트 테이터를 지정한다. (엑세스)

CONNECT BY

  • 다음에 전개될 자식 데이터를 지정하는 구문이다. (조인)

PRIOR

  • CONNECT BY 절에 사용되며, 현재 읽은 컬럼을 지정한다.
  • PRIOR 자식 = 부모 형태를 사용하면 계층구조에서 자식 -> 부모 방향으로 데이터를 전개하는 순방향전개를 한다.
  • 반대로 PRIOR 부모 = 자식 형태를 사용하면 계층구조에서 부모 -> 자식 방향으로 데이터를 전개하는 역방향전개를 한다.

NOCYCLE

  • 데이터를 전개하면서 이미 나타났던 동일한 데이터가 전개 중에 다시 나타난다면 이를 가리켜 사이클(Cycle)이 형성되었다고 한다. 이때 사이클이 발생한 데이터는 런타임 오류가 발생한다. 그렇지만 해당 옵션을 추가하면 사이클이 발생한 이후의 데이터는 전개하지 않는다.

ORDER SIBLINGS BY

  • 형제 노드(동일 LEVEL) 사이에서 정렬을 수행한다.

WHERE

  • 모든 전개를 수행한 후에 지정된 조건을 만족하는 데이터만 추출한다. (필터링)


가상 컬럼(Pseudo Column)

SQL 쿼리 내에서 계층 구조 정보를 제공하는 특별한 컬럼들이다. 이 컬럼들은 사용자가 데이터베이스에 직접 저장하지 않고, 계층형 질의(CONNECT BY 절을 사용하는 쿼리) 실행 시 동적으로 생성되어 계층적 관계와 관련된 유용한 정보를 제공한다.

가상 컬럼 설명
LEVEL 현재 레코드가 계층 구조에서 어느 레벨에 위치하는지를 정수 값으로 반환한다. 루트 데이터면 1, 그 하위 데이터면 2 이다. 리프(Leaf) 데이터까지 1씩 증가한다.
CONNECT_BY_ISLEAF 전개 과정에서 해당 데이터가 리프 데이터이면 1, 아니면 0
CONNECT_BY_ISCYCLE 현재 노드가 순환 구조에 포함되어 있는지 여부를 나타낸다. 전개 과정에서 자식을 갖는데, 해당 데이터가 조상으로서 존재하면 1, 아니면 0이다. 이 컬럼을 사용하려면 CONNECT BY 절에 NOCYCLE 옵션이 포함되어 있어야 한다.
CONNECT_BY_ROOT 현재 전개할 데이터의 루트 데이터를 표시한다. 단항 연산자이다.
SYS_CONNECT_BY_PATH 지정된 컬럼에 대한 노드의 경로를 문자열로 반환한다. 이 함수는 경로를 추적할 때 유용하며, 예를 들어 특정 직원에 이르는 직급의 연쇄를 표시할 때 사용할 수 있다.

 

 

예시

SELECT last_name, LEVEL, CONNECT_BY_ISLEAF
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
ORDER BY LEVEL, last_name;
[ 실행 결과 ] 

last_name	LEVEL	CONNECT_BY_ISLEAF
---		---		---
Smith		1		0
Johnson		2		0
Williams	2		0
Jones		3		1
Brown		3		1
Davis		3		1

 

 

 

SELECT 	LEVEL, LPAD(' ', 4 * (LEVEL-1)) || , 사원 사원,
	관리자, CONNECT_BY_ISLEAF ISLEAF
FROM 사원 START WITH 관리자 IS NULL
CONNECT BY PRIOR 사원 = 관리자;
[ 실행 결과 ] 

LEVEL		사원		관리자		ISLEAF
---		---		---		---
1 		A 				0
2 	 	 B 		A 		1
2 	 	 C 		A 		0
3 		  D		C 		1
3 		  E		C 		1

 

 

 

SELECT 	LEVEL, LPAD(' ', 4 * (LEVEL-1)) || , 사원 사원,
	관리자, CONNECT_BY_ISLEAF ISLEAF
FROM 사원 START WITH 사원 = 'D'
CONNECT BY PRIOR 사원 = 관리자;
[ 실행 결과 ] 

LEVEL		사원		관리자		ISLEAF
---		---		---		---
1 		D 		C		0
2 	 	 C 		A 		0
3 	 	  A		 		1

 

 

 

SELECT 	CONNECT_BY_ROOT, 사원 루트사원,
	SYS_CONNECT_BY_PATH(사원, '/') 경로, 사원, 관리자
FROM 사원
START WITH IS NULL 관리자
CONNECT BY PRIOR 사원 = 관리자
[ 실행 결과 ] 
루트사원		경로		사원		관리자
---		---		---		---
A		/A		A
A		/A/B		B		A
A		/A/C		C		A
A		/A/C/D		D		C
A		/A/C/E		E		C

'DataBase > SQLD' 카테고리의 다른 글

그룹함수(Group Function)  (0) 2024.04.26
서브쿼리(Subquery)  (2) 2024.04.26
분산 데이터베이스의 투명성  (0) 2024.04.23
정규화(Normalization)  (0) 2024.04.23
파티셔닝(Partitioning)  (0) 2024.04.23

분할 투명성(Fragmentation Transparency) : 단편화

데이터가 여러 조각으로 나뉘어져 각각 다른 노드에 저장되는 것을 사용자로부터 숨긴다.
사용자는 데이터의 조각이 어떻게 분할되고 어디에 위치하는지 신경 쓰지 않고 데이터베이스를 통합적으로 다룰 수 있다.

위치 투명성(Location Transparency)

사용자가 데이터에 접근할 때 데이터가 실제로 어디에 저장되어 있는지 모르는 상태에서도 접근할 수 있다.
사용자는 위치에 구애받지 않고 데이터 요청을 할 수 있으며, 시스템이 알아서 데이터 위치를 찾아 처리한다.

지역사상 투명성(Local Mapping Transparency)

시스템이 데이터의 실제 물리적 저장 위치를 어떻게 데이터베이스의 논리적 구조에 매핑하는지를 사용자로부터 숨긴다.
이는 사용자가 데이터의 물리적인 저장 상세 사항을 알 필요 없이 작업을 수행할 수 있게 해준다.

중복 투명성(Replication Transparency)

데이터가 여러 위치에 복제되어 있어도 사용자는 단 하나의 일관된 데이터를 보고 있는 것처럼 작업할 수 있다.
시스템이 자동으로 모든 복제본의 동기화와 일관성을 유지한다.

장애 투명성(Failure Transparency)

시스템의 일부가 실패해도 그 실패가 사용자나 응용 프로그램에게 보이지 않도록 한다.
사용자는 시스템의 장애에도 불구하고 계속해서 데이터에 접근하고 작업을 수행할 수 있다.

병행 투명성(Concurrency Transparency)

여러 사용자가 동시에 데이터에 접근하고 작업을 수행할 때, 그들 간의 상호 작용을 사용자가 인식하지 못하도록 관리한다.
시스템은 자동으로 동시 접근을 조정하여 데이터 일관성과 무결성을 유지한다.

'DataBase > SQLD' 카테고리의 다른 글

서브쿼리(Subquery)  (2) 2024.04.26
계층형 질의(Hierarchical Query) - Oracle  (0) 2024.04.26
정규화(Normalization)  (0) 2024.04.23
파티셔닝(Partitioning)  (0) 2024.04.23
반정규화(Denormalization)  (0) 2024.04.23

정규화(Normalization)란?

데이터베이스 설계에서 중복을 최소화하고, 데이터의 무결성과 일관성을 유지하기 위해 사용되는 과정이다. 데이터를 효율적으로 조직하고, 중복을 제거하여 보다 효과적인 데이터 저장 방식을 구현하는 데 목적이 있다. 이는 데이터의 저장 공간을 절약하고, 데이터를 변경하거나 업데이트할 때 발생할 수 있는 오류의 가능성을 줄인다.

정규화 단계

  1. 제1정규형(1NF)

    • 모든 도메인이 원자값만을 포함
  2. 제2정규형(2NF)

    • 제1정규형을 만족하며,
    • 모든 주 식별자가 아닌 속성이 테이블의 후보키에 완전 함수적으로 의존해야 한다. (완전 함수 종속)
    • 즉, 부분적 함수 종속을 제거해야 한다.
    • ex.
      • BEFORE )) <통합 테이블> user_id, user_name, subject_code, subject_name
      • 이때, 위 테이블의 PK는 사용자아이디와 과목 코드인데, 사용자명은 사용자아이디에만 종속되고, 과목명은 과목코드에만 종속된다. (부분적 함수 종속)
      • AFTER )) <사용자 테이블> user_id, user_name <과목 테이블> subject_code, subject_name <사용자-과목 테이블> user_id, subject_code
      • 각 테이블에서 주 식별자가 아닌 속성들이 주 식별자에만 완전히 종속되고 있다. (완전 함수 종속)
  3. 제3정규형(3NF)

    • 제2정규형을 만족하며,
    • 모든 주 식별자가 아닌 속성이 테이블의 기본 키에만 의존해야 한다.
    • 즉, 이행적 종속(Transitive Dependency)을 제거해야 한다.
    • ex.
      • BEFORE )) <통합 테이블> student, major_id, major_name
      • 이때, major_id는 student에 종속적이고, major_name은 major_id에 종속적이다. (이행적 종속) major_name -> major_id -> student
      • AFTER )) <학생-전공 테이블> student, major_id <전공 테이블> major_id, major_name
  4. BCNF(Boyce-Codd Normal Form)

    • 제3정규형을 만족하며,
    • 모든 결정자가 후보 키가 되는 정규형
    • 이때 결정자란, 어떤 속성의 값이 다른 속성의 값을 유일하게 결정할 수 있는 속성 집합을 말한다.
    • 후보키란, 그 중 하나가 주키(Primary Key)로 선택되어 사용되는 키이다. 따라서 한 테이블에 여러 후보키가 존재할 수 있다.
    • 모든 함수적 종속성 𝑋→𝑌 에 대해, X가 슈퍼키(superkey)일 때 만족
    • 이때 슈퍼키란, 후보키처럼 유일하게 식별할 수 있지만, 최소성을 만족시킬 필요는 없는 키이다.
    • ex.
      • BEFORE ))
  5. 제4정규형(4NF)

    • BCNF를 만족하며,
    • 다치 종속을 제거한다.
    • 모든 다치 종속이 후보키에 의해 결정될 때 4NF에 도달합니다.
  6. 제5정규형(5NF):

    • 조인 종속성을 통해 더 이상 분해할 수 없을 때까지 테이블을 분해

'DataBase > SQLD' 카테고리의 다른 글

계층형 질의(Hierarchical Query) - Oracle  (0) 2024.04.26
분산 데이터베이스의 투명성  (0) 2024.04.23
파티셔닝(Partitioning)  (0) 2024.04.23
반정규화(Denormalization)  (0) 2024.04.23
식별자 (Identifiers)  (0) 2024.04.23

+ Recent posts