2. 관계형 데이터베이스
- 2. 관계형 데이터베이스
키
데이터베이스에서 튜플을 구분하기 위한 속성 또는 속성의 집합
키의 특성
- 유일성 : 하나의 키 값으로 튜플을 식별할 수 있는 특성
- 최소성 : 튜플을 식별하는 데 필요한 속성만으로 이루어져 있는 특성
키의 종류
슈퍼 키(유일성 O, 최소성 X) : 테이블 내의 레코드를 유일하게 식별할 수 있는 하나 이상의 속성 조합
- 유일성 : Key로 하나의 Tuple을 유일하게 식별할 수 있음.
후보 키(유일성 O, 최소성 O) : 슈퍼 키 중 최소성을 만족하는 속성들의 집합.
- 유일성 : Key로 하나의 Tuple을 유일하게 식별할 수 있음.
- 최소성 : 꼭 필요한 속성으로만 구성.
기본 키 : 후보 키 중 해당 레코드를 식별할 때 기준이 되는 메인 키
- 유일성 : 기본키를 구성하는 컬럼은 테이블에서 레코드를 식별할 수 있도록 유일해야 한다.
- 최소성 : 유일성을 만족하는 한도 내에서 최소한의 컬럼(하나 이상)으로 구성되어야 한다.
- 개체 무결성 : 기본키가 가지고 있는 값의 유일성을 보장받아야 한다. 동일한 값이 중복되어 저장될 수 없다.
- NOT NULL : NULL 값을 가지면 안 된다.
대체 키 : 후보 키 중 기본 키를 제외한 키다.
외래 키 : 다른 테이블의 기본 키를 참조하는 키다. 참조 무결성에 의해 참조하는 테이블의 기본 키 값과 동일하거나 NULL이어야 한다.
복합 키 : 두 개 이상의 컬럼을 묶어서 하나의 기본 키로 지정
무결성
데이터베이스에 저장된 데이터와 실제 데이터가 일치하는 정확성과, 데이터가 일정하게 유지되는 일관성을 의미한다.
- 개체 무결성 : 모든 테이블이 기본 키를 가져야 한다. 기본 키의 값은 NULL이 될 수 없으며 중복되지 않고 고유한 값을 가져야 한다.
- 도메인 무결성 : 테이블의 속성 값은 도메인(domain)에 속해야 한다. 도메인은 속성이 가질 수 있는 값의 집합을 의미한다.
- 참조 무결성 : 외래 키의 값은 참조하는 테이블의 기본 키 값과 동일하거나 NULL이어야 한다. 즉 릴레이션은 참조할 수 없는 외래키 값을 가질 수 없다.
뷰(View) (B)
사용자에게 접근이 허용된 자료만을 제한적으로 보여주기 위해 하나 이상의 기본 테이블로부터 유도된 가상 테이블
- 명령문
- 정의 : CREATE
- 제거 : DROP
- 장점
- 질의문 쉽게 작성
- 특정 조건을 만족하는 튜플들로 뷰를 미리 만들어놓으면, 사용자가 WHERE 절 없이 뷰를 검색해도 특정 조건을 만족하는 데이터를 검색 가능
- GROUP BY, 집계 함수, 조인 등을 이용해 뷰를 미리 만들어놓으면, 복잡한 SQL문을 작성하지 않아도 SELECT 절과 FROM 절만으로 원하는 질의 가능
- 데이터 보안 유지 도움
- 뷰를 미리 정의하고 사용자가 자신에게 제공된 뷰를 통해서만 데이터에 접근하도록 권한을 설정하면, 뷰에 포함되지 않은 데이터를 사용자로부터 보호할 수 있다.
- 데이터 관리 용이
- 제공된 뷰에 포함되지 않은 기본 테이블의 다른 부분은 사용자가 신경 쓸 필요 없다
- 제공된 뷰와 관련 없는 다른 테이블의 변화에도 영향을 받지 않는다.
- 질의문 쉽게 작성
인덱스
데이터베이스에서 튜플의 검색 성능을 높이기 위해 속성 값과 튜플이 저장된 주소를 저장하는 것.
책의 색인처럼 작동하며, 키-값 형태로 '속성 값-튜플 주소'를 인덱스 테이블에 저장한다. 인덱스 테이블은 속성 값을 기준으로 정렬 상태를 유지한다.
Employee
테이블에서 EMPNO
컬럼에 EmpnoIndex
를 걸면 위와 같은 그림이 된다. 인덱스 값이 있고 포인터가 실제 데이터 레코드를 가리키고 있다는 것을 알 수 있다.
인덱스의 주요 개념
검색 성능 향상:
- 인덱스는 특정 컬럼이나 컬럼들의 조합에 대한 정보를 미리 정렬된 구조로 저장합니다. 이렇게 저장된 인덱스를 이용하면 데이터베이스는 전체 테이블을 스캔(Full Scan)하지 않고도 원하는 데이터를 빠르게 찾을 수 있습니다.
기본 구조:
- 인덱스는 일반적으로 B-트리(B-Tree)나 해시(Hash) 구조로 구현됩니다. B-트리 구조는 범위 검색이 효율적이며, 해시 인덱스는 정확히 일치하는 검색에 매우 빠르게 동작합니다.
인덱스의 장단점
- 장점
- 검색 성능 향상
- 인덱스 테이블에 데이터가 정렬되어 있어서 검색 속도가 빠르다
- 정렬된 결과 반환
- 인덱스가 설정된 컬럼을 기준으로 정렬된 데이터를 쉽게 얻을 수 있습니다
- 유니크 인덱스를 통한 데이터 무결성 보장:
- 유니크 인덱스를 사용하면 특정 컬럼이 고유한 값을 가지도록 보장할 수 있습니다. 이는 데이터 무결성을 유지하는 데 중요한 역할을 합니다.
- 조인 성능 향상:
- 인덱스는 테이블 간의 조인(join) 작업의 성능을 향상시키는 데에도 도움을 줍니다. 인덱스가 있는 컬럼을 기준으로 조인을 수행하면, 데이터베이스는 필요한 데이터만 효율적으로 가져올 수 있습니다.
- 검색 성능 향상
- 단점
- 쓰기 성능 저하:
- 인덱스는 데이터를 삽입, 업데이트 또는 삭제할 때마다 갱신되어야 합니다. 따라서 인덱스가 많을수록 쓰기 작업의 성능이 저하될 수 있습니다. 대량의 데이터를 자주 삽입하거나 수정해야 하는 환경에서는 이로 인해 성능 문제가 발생할 수 있습니다.
- 디스크 공간 증가:
- 인덱스는 테이블과 별도로 저장되는 구조이기 때문에, 인덱스의 수와 크기에 따라 디스크 공간이 많이 필요할 수 있습니다. 특히, 대규모 데이터베이스에서는 인덱스로 인한 디스크 사용량이 상당히 증가할 수 있습니다.
- 복잡한 관리:
- 여러 인덱스가 존재할 경우, 어떤 인덱스를 생성하거나 삭제할지, 그리고 어떻게 최적화할지에 대한 관리가 복잡해질 수 있습니다. 잘못된 인덱스 설계는 오히려 성능 저하를 초래할 수 있습니다.
- 불필요한 인덱스의 존재:
- 쿼리 패턴이 자주 변경되거나 예측할 수 없을 때, 불필요한 인덱스가 존재할 수 있습니다. 이 경우, 인덱스는 관리 비용만 증가시키고 실제 성능 향상에는 기여하지 않습니다.
- 쓰기 성능 저하:
주요 인덱스 유형
- 클러스터 인덱스는 페이지를 알기 때문에 바로 그 페이지를 펴는 것
- 넌 클러스터 인덱스는 뒤에 목차에서 찾고자 하는 내용의 페이지를 찾고 그 페이지로 이동하는 것.
- 테이블 스캔은 처음부터 한 장씩 넘기면서 내용을 찾는 것
클러스터형 인덱스(Clustered Index)
특징:
- 테이블의 실제 데이터가 인덱스 순서에 따라 정렬되어 저장됩니다. 데이터 입력, 수정, 삭제 시 항상 정렬 상태를 유지한다
- 테이블 당 하나만 존재할 수 있습니다. 클러스터드 인덱스를 따로 지정하지 않으면, 기본 키(primary key)가 클러스터드 인덱스가 된다. 즉, 테이블 생성 시 Primary Key(PK)를 지정하면, 그 칼럼은 자동으로 Clustered Index가 만들어진다.
사용 예시:
- 테이블 데이터가 자주 업데이트 되지 않는 경우
- MAX, MIN, COUNT등의 쿼리로 범위 또는 Group By 등의 조회를 하는 경우
- 항상 정렬 된 방식으로 데이터를 반환해야하는 경우
- 테이블은 정렬되어있기 때문에 ORDER BY 절을 활용해 모든 테이블 데이터를 스캔하지 않고 원하는 데이터를 조회할 수 있다.
- 읽기 작업이 월등히 많은 경우, 이때 매우 빠르다.
장점: 범위 검색 및 순차적인 데이터 접근에 매우 빠릅니다. 물리적으로 정렬되어 있어 검색 속도가 Non-Clustered Index 보다 더 빠르다.
단점: 삽입과 업데이트 작업에서 데이터의 물리적 재정렬이 필요할 수 있어 성능이 저하될 수 있습니다.
비클러스터형 인덱스(Non-Clustered Index)
- 특징: 인덱스는 별도의 구조로 저장되며, 실제 데이터의 포인터를 포함합니다. 하나의 테이블에 여러 개의 비클러스터형 인덱스를 생성할 수 있습니다.
- 사용 예시:
- where절이나 Join 절과 같이 조건문을 활용하여 테이블을 필터링 하고자 할 경우
- 데이터가 자주 업데이트 될 경우
- 특정 컬럼이 쿼리에서 자주 사용 될 경우
- 장점: 다양한 쿼리 조건에 맞게 다수의 인덱스를 생성할 수 있습니다.
- 단점: 여러 개의 인덱스가 있으면 삽입, 삭제, 수정 시 성능이 저하될 수 있습니다.
유니크 인덱스(Unique Index)
- 특징:
- 고유성 보장: 특정 컬럼이나 컬럼 조합이 고유한 값을 가지도록 보장합니다.
- 자동 생성 가능: 테이블의 기본 키에 대해 자동으로 생성됩니다. 따라서 기본 키는 항상 고유한 값을 가져야 하며, 이는 유니크 인덱스에 의해 보장됩니다
- NULL 처리: 대부분의 데이터베이스 시스템(ex. MySQL, Oracle, PostgreSQL, SQL Server)에서는 유니크 인덱스가 설정된 컬럼에
NULL
값을 여러 개 삽입할 수 있습니다. 이는NULL
값이 "정의되지 않은 값"으로 간주되며, 서로 비교할 수 없는 값이기 때문에 발생합니다.
- 사용 예시: 중복을 허용하지 않아야 하는 컬럼(예: 사용자 이메일, 주민등록번호 등)에 사용됩니다.
- 장점:
- 데이터 무결성 보장
- 중복 데이터 방지
- 검색 성능 향상:
- 유니크 인덱스는 고유성을 보장하는 것 외에도 일반 인덱스와 마찬가지로 특정 쿼리에서 검색 성능을 향상시킬 수 있습니다. 데이터베이스는 유니크 인덱스를 사용하여 해당 컬럼의 데이터를 빠르게 검색할 수 있습니다.
- 단점:
- 성능 문제: 삽입 또는 업데이트 시 중복 여부를 확인해야 하므로 성능에 영향을 미칠 수 있습니다. 특히 대량의 데이터를 처리하는 경우 이러한 성능 저하가 더 두드러질 수 있습니다.
유니크 인덱스와 기본 키의 차이점
기본 개념
유니크 인덱스: 특정 컬럼 또는 컬럼 조합이 고유한 값을 가지도록 보장하는 인덱스입니다. 동일한 값을 가진 두 레코드가 존재할 수 없도록 합니다.
기본 키(Primary Key): 테이블의 각 레코드를 고유하게 식별하는 컬럼 또는 컬럼 조합입니다. 기본 키는 각 레코드가 유일하게 식별될 수 있도록 하며, 자동으로 유니크 인덱스와 NOT NULL 제약 조건이 적용됩니다.
데이터 무결성
유니크 인덱스: 데이터의 중복을 방지하여 특정 컬럼에 고유한 값을 유지합니다. 다만, 유니크 인덱스는
NULL
값을 허용할 수 있습니다(일부 DBMS에서는NULL
값을 중복으로 간주하지 않음).기본 키: 데이터 무결성을 더 강력하게 보장합니다. 기본 키는 유니크 인덱스를 포함하며, 해당 컬럼은 반드시 값을 가져야 하고
NULL
값을 가질 수 없습니다.
적용 범위
유니크 인덱스: 테이블 내 여러 컬럼에 설정할 수 있습니다. 하나의 테이블에 여러 개의 유니크 인덱스를 가질 수 있으며, 이는 중복 방지 외에도 검색 성능 최적화에 사용될 수 있습니다.
기본 키: 테이블 당 하나만 설정할 수 있습니다. 기본 키로 설정된 컬럼(또는 컬럼 조합)은 테이블 내에서 각 레코드를 고유하게 식별합니다.
제약 조건
유니크 인덱스: 고유성을 보장하지만, 기본 키처럼 다른 테이블과의 관계를 직접 정의하지 않습니다.
기본 키: 외래 키(foreign key)를 통해 다른 테이블과의 관계를 설정하는 데 중요한 역할을 합니다. 기본 키는 다른 테이블에서 외래 키로 참조될 수 있습니다.
동시에 사용하는 경우
기본 키 외에도 다른 컬럼에서 중복을 허용하지 않아야 하는 경우: 예를 들어, 사용자 테이블에서 사용자 ID를 기본 키로 설정하고, 이메일 주소에 유니크 인덱스를 설정하여 중복된 이메일이 입력되지 않도록 합니다.
기본 키는 단일 컬럼이지만, 다른 컬럼 조합에 대해 고유성을 보장해야 할 때: 예를 들어, 기본 키가
ID
컬럼인 경우에도,first_name
과last_name
의 조합이 유니크해야 한다면, 이 조합에 유니크 인덱스를 추가할 수 있습니다.
복합 인덱스(Composite Index)
- 특징: 두 개 이상의 컬럼을 결합하여 만든 인덱스입니다. 여러 컬럼을 함께 검색할 때 성능을 최적화할 수 있습니다.
- 사용 예시: 복수의 컬럼을 결합하여 자주 사용되는 쿼리에서 성능을 높이는 데 사용됩니다. 예를 들어,
WHERE
절에서 두 개 이상의 컬럼이 자주 사용되는 경우 유리합니다. - 장점: 여러 컬럼을 결합하여 검색 성능을 최적화할 수 있습니다.
- 단점: 인덱스의 컬럼 순서가 중요하며, 잘못된 순서로 인덱스를 생성하면 성능이 저하될 수 있습니다.
인덱스 사용 시 고려사항
인덱스를 사용하면 데이터 검색 속도에서 이점이 있다. 하지만 데이터를 추가하면 데이터를 재정렬해야 하므로 오히려 처리 비용이 증가할 수 있다.
또한, 튜플의 삭제 연산이 발생하는 경우 인덱스 테이블에서 데이터는 '사용하지 않음' 처리가 되지만, 실제로 삭제되지 않고 테이블에 남아 있다. 따라서, 삭제 연산이 빈번하게 일어나면 인덱스 테이블 크기는 일정하지만 실제로 사용되는 데이터는 적어서 성능이 저하될 수 있다.
- 적절한 컬럼 선택: 모든 컬럼에 인덱스를 적용하는 것은 비효율적일 수 있습니다. 자주 사용되는 검색 조건이나 조인(join)에서 자주 사용되는 컬럼에 인덱스를 설정하는 것이 좋습니다.
- 인덱스 관리: 데이터베이스가 커지고 쿼리 패턴이 변할 때 인덱스를 적절히 관리하고 최적화하는 것이 중요합니다.
인덱스의 컬럼 선택 기준
이러한 요소들은 인덱스의 효율성을 극대화하고, 데이터베이스의 성능을 최적화하는 데 중요합니다.
자주 사용되는 쿼리의 검색 조건
WHERE 절에 자주 사용되는 컬럼: 인덱스를 추가하는 가장 중요한 기준 중 하나는 해당 컬럼이
WHERE
절에서 자주 사용되는지 여부입니다. 자주 검색되는 컬럼에 인덱스를 추가하면 검색 속도가 크게 향상됩니다.JOIN 절에 사용되는 컬럼: 두 개 이상의 테이블을 조인할 때 사용되는 컬럼에 인덱스를 추가하면 조인 성능이 향상됩니다.
ORDER BY, GROUP BY 절에 사용되는 컬럼: 정렬이나 그룹화가 자주 이루어지는 컬럼에 인덱스를 추가하면 이러한 작업의 성능이 향상됩니다.
데이터의 카디널리티(Cardinality)
고유한 값이 많은 컬럼: 인덱스는 고유한 값이 많을수록 효과적입니다. 예를 들어,
user_id
와 같이 고유한 값이 많은 컬럼은 인덱스를 통해 큰 성능 향상을 얻을 수 있습니다. 반면,gender
와 같이 값의 종류가 적은 컬럼은 인덱스의 효과가 떨어질 수 있습니다.선택도(Selectivity): 특정 값이 선택될 확률이 높다면 인덱스의 효과가 큽니다. 예를 들어, 인덱스를 사용하여 자주 조회되는 값을 신속하게 찾을 수 있습니다.
쿼리의 사용 빈도
- 자주 사용되는 쿼리: 특정 쿼리가 자주 사용된다면, 해당 쿼리에서 자주 참조하는 컬럼에 인덱스를 추가하는 것이 유리합니다. 자주 사용되지 않는 쿼리에는 굳이 인덱스를 추가할 필요가 없을 수 있습니다.
데이터 수정 빈도
쓰기 작업이 많은 컬럼: 데이터의 삽입, 삭제, 수정 작업이 빈번하게 일어나는 컬럼에 인덱스를 추가하면 성능에 부정적인 영향을 줄 수 있습니다. 인덱스는 데이터 변경 시마다 갱신되어야 하므로, 잦은 변경이 있는 컬럼은 신중하게 고려해야 합니다.
읽기 작업이 많은 컬럼: 반면, 읽기 작업이 자주 발생하는 컬럼에는 인덱스를 추가하는 것이 유리합니다. 읽기 성능을 크게 개선할 수 있기 때문입니다.
데이터의 크기 및 테이블 구조
대용량 테이블: 큰 테이블의 경우 인덱스가 필수적입니다. 전체 테이블을 스캔하는 것보다 인덱스를 사용하는 것이 훨씬 더 효율적입니다.
테이블의 구조: 테이블의 구조, 특히 테이블이 자주 조인되는 방식도 고려해야 합니다. 여러 테이블을 자주 조인해야 하는 경우, 각 테이블의 조인 키에 인덱스를 추가하는 것이 중요합니다.
복합 인덱스 사용
복합 인덱스(Composite Index): 여러 컬럼을 결합한 인덱스가 필요할 때는 쿼리에서 자주 함께 사용되는 컬럼들을 기준으로 복합 인덱스를 생성할 수 있습니다. 단, 복합 인덱스의 컬럼 순서는 쿼리에서 사용되는 순서와 일치해야 최대 효과를 발휘합니다.
선두 컬럼: 복합 인덱스의 첫 번째 컬럼이 가장 자주 검색되거나 정렬되는 컬럼이어야 인덱스가 제대로 활용될 수 있습니다.
데이터 분포
- 균등한 데이터 분포: 인덱스가 효과적이려면 데이터가 균등하게 분포되어 있는 것이 좋습니다. 특정 값에 데이터가 몰려 있으면 인덱스의 성능 향상 효과가 적어질 수 있습니다.
인덱스의 사용 예
- 대량 데이터에서 특정 레코드 검색: 데이터 양이 방대하며 데이터 변경보다 검색을 자주 사용하는 경우. 예를 들어, 사용자 테이블에서 특정 사용자의 정보를 찾는 경우, 사용자 ID에 인덱스가 있으면 매우 빠르게 검색할 수 있습니다.
- 중복 방지: 이메일과 같이 중복이 허용되지 않는 컬럼에 유니크 인덱스를 설정하여 중복 데이터를 방지할 수 있습니다.
해시 테이블 인덱스
속성 값으로 해시 값을 계산해 인덱싱하는 방법
키(Key)를 특정 해시 함수(Hash Function)를 통해 해싱한 후 나온 결과(정수)를 배열의 인덱스로 사용하여 값(Value)를 찾는다.
해시의 특성상 속성 값을 그대로 검색해야 해서 검색하려는 값을 온전히 입력할 때만 사용 가능하므로, 검색 속도가 빠른데도 자주 사용하지 않는 방식
검색 성능은 해시 함수의 성능과 해시 테이블의 크기에 좌우된다.
장점(Advantage)과 단점(Disadvantage)
- 해싱된 키(Hash Key)를 가지고 배열의 인덱스로 사용하기 때문에 삽입, 삭제, 검색이 매우 빠르다.
- 해시 함수(Hash Function)를 사용하는데 추가적인 연산이 필요하다.
- 적은 데이터 저장시 구현 방식에 따라 연결리스트(Linked List)를 사용하는 경우 오버 헤드의 부담이 생기고, 캐시 효율이 떨어진다.
- 해시 테이블(Hash Table)의 크기가 유한적이고 해시 함수(Hash Function)의 특성상 해시 충돌(Hash Collision)이 발생할 수 밖에 없다.
- 충돌이 없거나 적으면 O(1)의 상수 시간에 가까워지고, 충돌이 발생하면 할수록 성능은 점점 O(n)에 가까워진다.
문제점(Problem)
- 해시 충돌(Hash Collision) : 해싱된 키(Hash Key)가 중복되어 해당 버킷(Bucket)에 이미 레코드가 존재하는 현상을 말한다.
- 오버플로우(Overflow) : 해시 충돌(Hash Collision)이 버킷(Bucket)에 할당된 슬롯(Slot) 수보다 많이 발생하면 더 이상 버킷에 값을 넣을 수 없는 현상을 말한다.
- 클러스터링(Clustering) : 연속된 레코드에 데이터가 몰리는 현상을 말한다.
B +/- 트리 인덱스
인덱스 테이블을 구현할 때 많이 사용되는 방식. B는 Balanced를 의미한다.
구분
B + 트리 : 단말 노드에만 데이터를 저장하고 단말 노드 간에는 연결 리스트로 연결
B - 트리 : 모든 노드에 데이터가 저장
장점
- 데이터의 삽입, 갱신, 삭제 등에 드는 작업 비용 절감
- 속성을 범위로 검색할 수 있어 효율적 검색 가능
B - 트리 인덱스
균형 이진 트리(Balanced Tree)의 한 종류
B-트리 인덱스의 주요 특징
- 균형된 트리 구조:
- B-트리는 모든 리프 노드가 동일한 깊이를 가지는 균형 트리입니다. 즉, 모든 리프 노드가 트리의 최하단에 위치하고, 루트 노드에서 리프 노드까지의 거리가 동일합니다. 이 균형 덕분에 삽입, 삭제, 검색 작업이 일정한 성능을 유지할 수 있습니다.
- 노드 구조:
- B-트리의 각 노드는 여러 개의 키(key)와 포인터(pointer)를 포함할 수 있으며, 이로 인해 노드 내에서 데이터를 효율적으로 관리할 수 있습니다. 노드에는 최대 수의 키와 포인터가 저장될 수 있고, 자식 노드의 범위를 가리키는 포인터가 포함됩니다.
- 다중 분기:
- B-트리는 다중 분기를 허용하는 트리 구조입니다. 일반적인 이진 트리와 달리, B-트리는 하나의 노드가 여러 개의 자식 노드를 가질 수 있어 트리의 높이를 줄일 수 있습니다. 이는 대규모 데이터셋에서도 빠른 탐색이 가능하게 만듭니다.
- 정렬된 데이터:
- B-트리 인덱스는 데이터를 정렬된 형태로 유지합니다. 각 노드의 키 값들은 항상 정렬된 상태로 저장되며, 이를 통해 검색 속도가 매우 빠릅니다. 특히
ORDER BY
,BETWEEN
,>
,<
와 같은 범위 검색에서 매우 효율적입니다.
- B-트리 인덱스는 데이터를 정렬된 형태로 유지합니다. 각 노드의 키 값들은 항상 정렬된 상태로 저장되며, 이를 통해 검색 속도가 매우 빠릅니다. 특히
- 동적 확장성:
- B-트리는 삽입과 삭제 작업이 이루어질 때마다 트리가 자동으로 균형을 유지합니다. 새로운 데이터가 삽입되거나 기존 데이터가 삭제되면 트리가 스스로 재구성되며, 이는 트리의 깊이가 급격히 증가하는 것을 방지합니다.
- 고정된 성능:
- B-트리의 성능은 트리의 높이에 비례합니다. 트리의 높이는 데이터의 양에 로그(log) 수준으로 비례하기 때문에, 대규모 데이터베이스에서도 일정한 검색, 삽입, 삭제 성능을 유지할 수 있습니다.
B-트리 인덱스의 작동 방식
- 검색(Search): 루트 노드에서 시작하여 해당 키가 어느 하위 노드에 위치하는지 확인합니다. 이 과정을 반복하여 리프 노드까지 내려가면, 최종적으로 원하는 키를 찾을 수 있습니다. 이 과정은 로그 수준의 시간이 소요됩니다.
- 삽입(Insertion): 새로운 키를 삽입할 때 해당 키가 들어갈 위치를 먼저 찾습니다. 만약 삽입할 노드가 가득 찼다면, 노드를 분할하여 트리의 균형을 유지합니다.
- 삭제(Deletion): 키를 삭제할 때는 먼저 해당 키를 찾은 후 삭제합니다. 만약 삭제로 인해 노드의 키가 너무 적어지면, 노드를 병합하여 균형을 회복합니다.
B-트리 인덱스의 장단점
장점
- 범위 검색에 효율적: B-트리는 데이터가 정렬된 상태로 저장되기 때문에 범위 검색(
BETWEEN
,>
,<
)에서 매우 효율적입니다. - 균형 유지: 트리가 항상 균형을 유지하므로, 대규모 데이터셋에서도 일정한 성능을 보장합니다.
- 동적 확장성: 삽입, 삭제가 빈번한 환경에서도 트리 구조가 자동으로 조정되므로, 성능이 급격히 떨어지지 않습니다.
- 다중 분기: 이진 트리와 달리 다중 분기를 사용하기 때문에 데이터가 많아져도 트리의 높이가 낮게 유지됩니다. 이는 트리 탐색 성능을 더욱 향상시킵니다.
단점
- 인덱스 크기: B-트리 인덱스는 모든 노드가 다중 분기를 갖기 때문에 인덱스 자체가 큰 디스크 공간을 차지할 수 있습니다.
- 추가적인 쓰기 부하: 삽입 및 삭제 작업 시 노드 분할 또는 병합이 일어나면 인덱스 유지 보수에 추가적인 오버헤드가 발생할 수 있습니다.
- 특정 조건의 비효율성: 해시 인덱스와 같은 정확한 값 검색에 비해 특정 조건에서는 성능이 떨어질 수 있습니다.
B + 트리
B+ 트리는 B-트리의 개선된 버전으로, 특히 범위 검색과 순차적인 데이터 접근에 최적화된 구조입니다.
데이터베이스에서 매우 자주 사용되며, 대규모 데이터셋에서 일관된 성능을 제공하는 인덱스 구조
B+ 트리의 주요 특징
- 모든 데이터가 리프 노드에 저장:
- B+ 트리에서 실제 데이터(키 값)는 모두 리프(leaf) 노드에 저장됩니다. 내부 노드는 데이터의 경로를 안내하는 데 사용되며, 리프 노드는 정렬된 순서로 연결 리스트 형태로 연결됩니다. 이로 인해, 데이터의 검색과 순차적인 접근이 매우 효율적입니다.
- 균형된 트리 구조:
- B+ 트리도 B-트리와 마찬가지로 모든 리프 노드가 동일한 깊이를 가지는 균형 트리입니다. 이는 특정 키 값을 검색할 때 항상 일정한 시간 복잡도를 유지할 수 있게 합니다.
- 리프 노드 간 연결(Linked Leaf Nodes):
- 리프 노드들은 모두 서로 연결 리스트 형태로 연결되어 있습니다. 이를 통해, 특정 범위의 데이터를 순차적으로 읽어야 할 때 매우 빠른 접근이 가능해집니다. 예를 들어,
BETWEEN
이나ORDER BY
쿼리에서 성능이 뛰어납니다.
- 리프 노드들은 모두 서로 연결 리스트 형태로 연결되어 있습니다. 이를 통해, 특정 범위의 데이터를 순차적으로 읽어야 할 때 매우 빠른 접근이 가능해집니다. 예를 들어,
- 내부 노드와 리프 노드의 분리:
- B+ 트리에서 내부 노드는 실제 데이터를 저장하지 않고, 오직 하위 노드를 가리키는 포인터와 범위만을 저장합니다. 모든 데이터는 리프 노드에만 저장되기 때문에, 리프 노드가 더 많은 데이터를 포함할 수 있어 트리의 높이가 낮아지고 검색 속도가 빨라집니다.
B+ 트리의 작동 방식
- 검색(Search):
- 루트 노드에서 시작해 트리를 내려가며, 찾고자 하는 키 값의 범위에 따라 적절한 자식 노드로 이동합니다. 최종적으로 리프 노드에 도달하면, 해당 리프 노드에 저장된 데이터 중에서 정확한 키 값을 찾습니다.
- 삽입(Insertion):
- 새로운 키를 삽입할 위치를 찾은 후, 해당 리프 노드에 키를 삽입합니다. 만약 리프 노드가 가득 찼다면 노드를 분할하고, 상위 노드에 새로운 경로 정보를 추가합니다. 이러한 과정은 트리 전체의 균형을 유지합니다.
- 삭제(Deletion):
- 삭제할 키를 포함한 리프 노드를 찾아 삭제합니다. 리프 노드의 키가 너무 적어져서 균형이 깨질 경우, 인접한 노드와 병합하거나 재분배를 통해 트리의 균형을 유지합니다.
B+ 트리의 장단점
장점
- 범위 검색에 매우 효율적:
- 리프 노드들이 연결 리스트 형태로 연결되어 있어, 순차적으로 데이터를 탐색할 때 매우 빠릅니다.
BETWEEN
,ORDER BY
와 같은 범위 쿼리에서 특히 뛰어난 성능을 발휘합니다.
- 리프 노드들이 연결 리스트 형태로 연결되어 있어, 순차적으로 데이터를 탐색할 때 매우 빠릅니다.
- 효율적인 디스크 I/O:
- B+ 트리는 리프 노드가 디스크 블록에 효율적으로 맞도록 설계되어 있어, 디스크 I/O 작업이 최소화됩니다. 이는 대용량 데이터베이스에서 매우 중요한 성능 요인입니다.
- 고정된 트리 높이:
- 데이터가 리프 노드에만 저장되기 때문에 트리의 높이가 낮게 유지됩니다. 이는 검색, 삽입, 삭제 작업에서 일관된 성능을 제공합니다.
- 연속된 데이터 접근 최적화:
- 리프 노드 간의 연결 리스트 구조 덕분에, 연속된 데이터를 효율적으로 탐색할 수 있어, 범위 검색 시 매우 유리합니다.
단점
- 추가적인 연결 리스트 유지 비용:
- 리프 노드 간의 연결 리스트를 유지하는 데 약간의 오버헤드가 발생할 수 있습니다. 하지만, 범위 검색에서의 이점이 이 오버헤드를 상쇄합니다.
- 더 많은 메모리 사용:
- B+ 트리는 내부 노드와 리프 노드에 각각 데이터를 저장하므로, 상대적으로 더 많은 메모리가 필요할 수 있습니다.
B-트리와 B+ 트리의 비교
- 데이터 저장 위치:
- B-트리: 데이터는 모든 노드(내부 및 리프 노드)에 저장될 수 있습니다.
- B+ 트리: 데이터는 오직 리프 노드에만 저장되며, 내부 노드는 경로 정보만 저장합니다.
- 범위 검색 성능:
- B-트리: 범위 검색 시 노드 간 순차적인 탐색이 어려워 성능이 다소 떨어질 수 있습니다.
- B+ 트리: 리프 노드 간 연결로 인해 범위 검색이 매우 효율적입니다.
- 트리의 높이:
- B-트리: 데이터가 내부 노드에도 저장되므로 트리의 높이가 상대적으로 클 수 있습니다.
- B+ 트리: 모든 데이터가 리프 노드에만 저장되므로 트리의 높이가 낮게 유지됩니다.
ORM(Object-Relational Mapping)
체지향 프로그래밍 언어에서 사용하는 객체와 관계형 데이터베이스의 테이블을 자동으로 연결해 주는 기술
개발자는 데이터베이스와 상호작용할 때 SQL을 직접 작성하지 않고도, 객체 지향적인 코드로 데이터베이스 작업을 수행할 수 있습니다.
ORM의 주요 개념
- 객체와 테이블의 매핑:
- ORM은 프로그래밍 언어에서 사용하는 클래스(객체)와 데이터베이스의 테이블을 매핑합니다. 클래스의 각 속성은 테이블의 컬럼에, 클래스의 인스턴스는 테이블의 레코드(행)에 대응합니다. 이를 통해 객체 지향 코드와 관계형 데이터베이스 간의 격차를 해소합니다.
- 자동 SQL 생성:
- ORM 도구는 객체의 메서드 호출이나 속성 접근에 따라 필요한 SQL 쿼리를 자동으로 생성합니다. 예를 들어, 객체를 데이터베이스에 저장할 때는
INSERT
쿼리가, 객체를 조회할 때는SELECT
쿼리가 자동으로 생성됩니다.
- ORM 도구는 객체의 메서드 호출이나 속성 접근에 따라 필요한 SQL 쿼리를 자동으로 생성합니다. 예를 들어, 객체를 데이터베이스에 저장할 때는
- 데이터베이스 무관성:
- ORM을 사용하면 코드가 특정 데이터베이스에 종속되지 않도록 할 수 있습니다. ORM 도구가 SQL을 생성하기 때문에, 데이터베이스 시스템을 변경하더라도 코드의 큰 수정 없이 호환될 수 있습니다.
- 트랜잭션 관리:
- ORM은 트랜잭션을 쉽게 관리할 수 있는 기능을 제공합니다. 여러 객체의 변경 사항을 하나의 트랜잭션으로 묶어 데이터의 일관성을 보장할 수 있습니다.
ORM의 장점
- 생산성 향상:
- SQL을 직접 작성할 필요 없이, 객체 지향적인 코드로 데이터베이스 작업을 수행할 수 있으므로 개발 속도가 빨라지고, 코드를 이해하기 쉬워집니다.
- 유지보수 용이성:
- 데이터베이스 관련 로직이 ORM에 의해 관리되므로, 데이터베이스 스키마가 변경되더라도 코드에서 직접 SQL을 수정할 필요가 줄어듭니다. 따라서 코드 유지보수가 쉬워집니다.
- 타입 안전성:
- ORM은 객체 지향 언어의 타입 시스템을 활용하므로, 데이터베이스와 상호작용할 때 타입 관련 오류를 줄일 수 있습니다.
- 자동화된 데이터베이스 작업:
- 객체 생성, 읽기, 업데이트, 삭제(CRUD) 작업이 자동화되어 코드 작성이 간편합니다.
- 복잡한 쿼리의 간단한 표현:
- ORM은 복잡한 조인이나 서브쿼리 등을 객체 지향적인 방식으로 간단하게 표현할 수 있도록 도와줍니다.
ORM의 단점
- 성능 오버헤드:
- SQL을 직접 작성하는 것에 비해 ORM은 일반적으로 성능이 떨어질 수 있습니다. 이는 ORM이 SQL을 자동 생성하는 과정에서 발생하는 오버헤드 때문입니다.
- 복잡한 쿼리 처리의 한계:
- ORM이 자동으로 생성하는 SQL이 복잡한 쿼리나 특정한 데이터베이스 최적화 기법을 완벽하게 지원하지 못할 수 있습니다. 이로 인해, 복잡한 쿼리의 경우 직접 SQL을 작성해야 하는 상황이 생길 수 있습니다.
- 초기 학습 곡선:
- ORM 도구를 처음 사용하는 경우, 이를 이해하고 적절하게 사용하는 데 시간이 필요할 수 있습니다.
- 추상화로 인한 제어 부족:
- ORM이 SQL을 자동 생성하므로, 개발자가 데이터베이스 작업을 세부적으로 제어하기 어려운 경우가 발생할 수 있습니다. 특히, 성능에 민감한 애플리케이션에서는 문제가 될 수 있습니다.
Reference
'CS > DB' 카테고리의 다른 글
1.데이터베이스의 종류 (0) | 2024.08.17 |
---|---|
인덱스 (0) | 2021.12.28 |
정규화 (0) | 2021.12.28 |
스프링 트랜잭션과 트랜잭션 전파 (0) | 2021.12.28 |
트랜잭션 격리수준 (0) | 2021.12.28 |