[DB] PK (Primary Key) ID 길이가 성능에 영향을 미칠까?

2024. 12. 11. 02:33·Database/SQL
728x90

 

Primary Key ?

  • PK (Primary Key)는 데이터베이스에서 각 행(row)을 고유하게 식별하기 위한 열(column)이다.
  • PK는 효율적인 데이터 검색, 외래 키 참조, 데이터 무결성 보장을 위해 사용된다.

 

PK 길이가 길어질 때의 문제점은 무엇일까?

  • 저장 공간 증가: 긴 PK는 테이블의 저장 공간을 늘리고, 외래 키로 참조되는 테이블에도 영향을 미친다.
  • 인덱스 크기 증가로 인한 검색 성능 저하: PK는 기본적으로 인덱스로 관리되며, 길이가 길수록 인덱스 크기가 증가하고 검색 속도가 느려진다.
  • 외래 키 테이블의 추가 비용: 외래 키가 긴 PK를 참조할 때, 외래 키 테이블도 더 많은 공간을 차지하게 된다.

 

PK 길이가 길어질 때 인덱스 크기 증가로 인한 검색 성능 저하에 대해서 더 자세히 알아보겠다.

 

 

  • PK는 기본적으로 클러스터드 인덱스(Clustered Index)로 관리된다.
    • MySQL은 PK를 기준으로 유사한 값들이 함께 조회되는 경우가 많다는 점에서 착안해, PK가 유사한 레코드들끼리 묶어서 저장한다. 유사한 것들을 묶는 것을 클러스터링이라고 하는데, 그래서 일반적으로 PK는 클러스터 인덱스(Clustered Index)라고도 불리며, 그 외의 일반적인 인덱스는 논클러스터 인덱스로 불린다. 그리고 이러한 클러스터링 특성 때문에 레코드의 저장이나 PK의 변경은 처리 속도가 느리다.(참고)
    • 그래서 클러스터드 인덱스는 테이블의 데이터가 PK 값 순서대로 정렬되며, 인덱스 노드와 데이터 페이지가 하나의 구조로 관리된다.
    • PK를 기반으로 자동 생성된 인덱스는 테이블의 데이터 정렬 및 검색에 사용되며, 모든 조회, 삽입, 삭제, 갱신 작업에 영향을 미친다.

 

 

Index란?

DB에서 index 는 단어 그대로 색인자의 역할을 한다. 보통 한 개의 테이블에는 수십 개의 column이 존재하며, MySQL은 데이터 조회 시 가장 첫 번째 column부터 차례대로 검색하기 시작한다. 만약 index 가 존재하지 않는다면 데이터를 조회할 때 언제나 테이블 전체를 Full scan 해야 하는데 이는 비용과 성능 면에서 매우 비효율적이다.

하지만 데이터가 Create, Update, Delete 되는 경우 Index도 함께 수정돼야 하기 때문에 index가 없는 경우보단 효율이 떨어진다. 즉 Read 성능을 살리고 CUD를 성능을 희생한다고 볼 수 있다. 따라서 잦은 수정이 필요한 테이블의 경우는 오히려 index를 활용하지 않는게 더 이로울 수 있다.(참고)

 

Page란?

Page(페이지)는 데이터베이스에서 데이터를 저장하는 기본 단위이다. MySQL에서는 innodb_page_size 시스템 변수로 4KB ~ 64 KB 사이 값 선택 가능하고, 기본 값은 16KB이다. B+Tree의 각 노드는 페이지로 구성되며, 각 페이지는 인덱스 키와 자식 노드 주소를 포함합니다. (B+Tree는 아래에서 더 자세하게 살펴보겠다.)

인덱스 페이지 내 키 값 구성 예시를 보면,

  • 인덱스 페이지 크기: 16KB (16 * 1024 = 16,384)
  • 인덱스 키 값: 28 Byte
    • 인덱스 키 영역: 16 Byte
    • 자식 노드 주소 영역: 12 Byte
    • 한 키 값의 전체 크기 = 16 + 12 = 28 Byte
  • 한 페이지에 저장 가능한 키 값 수 : 16,384/28 = 585개
    • 한 페이지에 약 585개의 키 값을 저장할 수 있다.

 

키 값 크기와 페이지 효율 비교하면 키 값이 작을수록 페이지에 저장 가능한 키 수가 증가하는 것을 볼 수 있다.

키 값 크기 16KB 페이지 내 저장 가능 키 수
20 bytes 16,384/20 = 819
28 bytes 16,384/28 = 585
36 bytes 16,384/36 = 455
64 bytes 16,384/64 = 256

 

그렇기에 페이지 크기와 키 값 크기의 관계를 보면,

  • 키 값 크기가 커질수록 한 페이지에 저장할 수 있는 키 값 수가 줄어든다.
  • 페이지 크기가 클수록 한 페이지에 더 많은 키 값을 저장할 수 있어 트리의 높이가 낮아진다.

 

그러면 페이지 크기가 크면 무조건 좋은가에 대한 생각이 들 수 있지만, 페이지 크기가 클수록 트리의 높이가 줄어들지만, 큰 페이지는 메모리 사용량과 디스크 I/O 비용이 증가할 수 있기 때문에 주의하여야 한다.

  • 디스크 I/O 비용 증가 : 데이터베이스는 필요한 데이터를 페이지 단위로 읽어온다. 그래서 페이지 크기가 크면 요청한 데이터 외에 불필요한 데이터도 함께 로드하게 된다.
    • 예로, 4KB 페이지 크기에서 100바이트의 데이터를 읽으면 약 4KB를 로드하지만, 64KB 페이지 크기에서는 동일한 100바이트의 데이터를 읽기 위해 64KB를 로드하게 된다. 페이지 크기를 너무 크게 잡을 시, 디스크에서 더 많은 데이터를 읽으므로 I/O 비용이 증가한다.
    • 또한, 페이지가 클수록 데이터를 수정할 때 변경된 작은 데이터(예: 100바이트)를 반영하기 위해 전체 페이지를 다시 저장해야 한다.
    • 큰 페이지 크기는 특정 데이터를 찾기 위해 더 많은 데이터를 탐색해야 하므로 랜덤 I/O 비용을 증가시킨다.

 

Page Split은 인덱스에 새로운 데이터가 삽입될 때 기존 페이지에 빈 공간이 부족하면 발생한다.
새로운 페이지를 생성하여 기존 데이터를 분리하고, 삽입 데이터를 적절한 위치에 배치한다.

(문제점) Page Split은 추가적인 디스크 I/O를 유발하며 성능 저하를 초래할 수 있다. 특히, 랜덤하게 생성되는 UUID는 Page Split이 빈번하게 발생한다.

 

 

MySQL 은 PK 를 설정하면 해당 값을 index 로 잡아 데이터를 B+tree 구조로 저장한다.

InnoDB의 클러스터링 인덱스도 사실상 B-Tree 구조로 관리된다. 

하지만 클러스터링 인덱스는 테이블의 데이터 자체를 포함하고 있으며, 다음과 같은 특징이 있다.

데이터와 인덱스의 결합

  • 클러스터링 인덱스는 B-Tree 구조로 정렬되어 있지만, 인덱스의 각 노드(리프 노드)는 테이블의 실제 레코드 자체를 포함 .
  • 클러스터링 인덱스를 통해 데이터를 찾으면, 바로 해당 레코드의 모든 데이터를 가져올 수 있음. 
  • 이를 인덱스-오거나이즈드 테이블(Index-Organized Table) 이라고도 부름

B+Tree 구조

  • 클러스터링 인덱스도 실제로는 B+Tree 구조에 기반하고 있음
  • 기본 키를 기준으로 데이터를 정렬하고, B-Tree 구조의 각 노드가 테이블의 레코드를 가리키는 것이 아니라 레코드를 포함하고 있는 형태임
  • 이 때문에 클러스터링 인덱스도 B+Tree 인덱스의 일종으로 간주할 수 있음.

(참고)

 

B+Tree?

B+Tree는 데이터베이스에서 인덱스를 관리하기 위해 사용되는 트리 자료 구조다. 모든 리프 노드가 동일한 깊이에 있으며, 리프 노드에는 실제 데이터의 위치(포인터)가 저장된다.

  • 각 노드는 키 값(PK)을 기준으로 정렬.
  • 리프 노드(Leaf Node)는 실제 데이터 행(Row)에 대한 포인터를 포함.
  • 비 리프 노드(Non-leaf Node)는 탐색 경로를 제공하며, 리프 노드로 이어짐. 

 

B+Tree의 구조

- 루트 노드: 트리의 최상단 노드. 검색 시작점.
- 중간 노드: 탐색 경로를 제공.
- 리프 노드: 실제 데이터 위치를 가리키는 포인터를 포함.


          [50]
         /    \
      [25]    [75]
     /   \    /   \
[1~24] [26~49] [51~74] [76~100]

 

  • 루트 노드: [50]
  • 중간 노드: [25], [75]
  • 리프 노드: [1~24], [26~49], [51~74], [76~100]

 

 

PK가 인덱스로 설정되면

  • 데이터는 PK 값 기준으로 정렬되며, 빠른 검색이 가능하다.
  • 키 값이 길어질수록 트리의 높이(Depth)가 증가하여 성능에 영향을 미친다.

 

그렇기 때문에 PK 가 길어지면, 아래와 같은 현상이 발생한다.

→ 인덱스 키 값 크기 증가

→ 인덱스 페이지에 담을 수 있는 인덱스 키 값 갯수 감소

→ B-Tree 깊이 증가

→ 디스크 읽기 증가

(참고)

 

예시 1) PK: bigint (Auto-increment)

  • PK 값이 짧고 순차적으로 증가하기 때문에 트리의 균형이 유지되고 노드에 더 많은 키 값을 저장할 수 있음.
    • 노드에 많은 키 값을 저장할 수 있어 트리의 높이가 낮음
  • 트리의 높이가 낮아 탐색 속도가 빠름.
    • 디스크 I/O가 최소화되어 검색 성능이 우수.

 

 

예시 2) PK: UUID

  • PK 값이 길고 랜덤하게 생성되므로 트리의 균형을 유지하기 어렵고, 노드에 저장 가능한 키 값 수가 줄어듦.
    • 노드 당 저장할 수 있는 키 값 수가 줄어들어 트리의 높이가 증가
  • 트리의 높이가 증가하여 탐색 속도가 느려짐.
    • 디스크 I/O가 증가하여 검색 성능이 저하.

 

 

 

[PK 선택 시 고려해야 할 사항]

1. 성능
2. 분산 시스템

-> UUID를 사용해야 하는 경우:
   데이터가 분산 환경에서 생성될 때.
   각 시스템 간 데이터 충돌을 방지해야 할 때.
   - 장점: 전역 고유성 보장.
   - 단점: 길이가 길고, 랜덤한 값이기 때문에 인덱스 정렬 효율이 떨어짐.


-> Auto-increment가 적합한 경우:
   단일 데이터베이스에서 간단한 고유성이 필요할 때.
   - 장점: 짧고 정렬된 값으로 성능이 좋음.
   - 단점: 분산 시스템에서 고유성을 보장하기 어려움.
728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Database > SQL' 카테고리의 다른 글

"조인(Join)" 완벽 이해하기  (1) 2024.12.26
데이터베이스 자료형에 대해 알아보자!  (0) 2024.12.18
[JPA] flush는 언제 일어날까?  (1) 2024.12.18
[DB] 트랜잭션, 격리수준에 대해서 알아보자.(+ 면접 준비)  (1) 2024.12.10
SQL 프로그래밍 (1) - 데이터베이스란?, MySQL란?, MySQL 설치, Workbench 활용  (0) 2022.02.02
'Database/SQL' 카테고리의 다른 글
  • 데이터베이스 자료형에 대해 알아보자!
  • [JPA] flush는 언제 일어날까?
  • [DB] 트랜잭션, 격리수준에 대해서 알아보자.(+ 면접 준비)
  • SQL 프로그래밍 (1) - 데이터베이스란?, MySQL란?, MySQL 설치, Workbench 활용
pink_salt
pink_salt
유익함을 주는 개발자가 되도록 keep going
  • pink_salt
    KeepGoingForever
    pink_salt
  • 전체
    오늘
    어제
    • 분류 전체보기 (117)
      • Project (7)
      • WEB study (3)
        • WEB(Springboot) (10)
        • Git, GitLab (13)
        • Clean code (1)
        • FrontEnd (3)
      • Study (21)
        • Algorithm (19)
        • 면접 준비 (2)
      • Cloud Computing (2)
        • AWS (2)
      • 프로그래밍 언어 (35)
        • Java (29)
        • Python (0)
        • javascript (6)
      • 운영체제 (0)
        • Linux (0)
      • Database (4)
        • MongoDB (8)
        • SQL (8)
      • 애플리케이션 개발 (1)
        • Android (1)
      • AI (1)
        • Deeplearning (1)
        • machinelearning (0)
      • Daily (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    gitlab
    언어
    코드프레소
    BFS
    Query
    빅오표기법
    MongoDB
    오블완
    티스토리챌린지
    mysql
    git branch
    무료코딩교육
    대외활동
    IT교육
    SW
    Java
    무료IT교육
    코딩이러닝
    코딩강의
    python
    codepresso
    spring boot
    dp
    객체지향
    Git
    SWEA
    자바
    개념
    Database
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
pink_salt
[DB] PK (Primary Key) ID 길이가 성능에 영향을 미칠까?
상단으로

티스토리툴바