[TIL] Real MySQL UUID

2025.03.16
·
9 min read

UUID?

  • Universally Unique Identifier

  • 국제인터넷 표준 기구 IETF 에서 정식 표준으로 채택된 고유 식별자임.

  • 128비트로 구성된 이진값

    • 16진수 헥사데시멀 문자열(32바이트) 로 표현된다.

      16진수 헥사데시멀?

      • 한 자리로 15까지 표현할 수 있다.

      • 0 ~ 9 다음에 A B C D E F 라는 문자를 사용한다

      • 16개의 기호를 사용하는 것이다.

        • 어떻게 구성되나

          • 128비트 이진값을 16진수로 변환해서 표현한다.

            • 이걸 32자리의 문자열로 나타낸다고 한다.

            • 예를 들어

              • 16진수 한 자리는 4비트(2 진수 4자리) 를 표현하고

              • 128비트를 4비트씩 끊는다면 총 32개의 16진수 자리가 나온다.

    • DB에서 보통

      • CHAR(32) 혹은 VARCHAR(36) 와 같은 문자열 타입으로 저장된다고 한다.

UUID 버전

  • 총 5개의 버전이 존재한다.

    • 버전 1

      • 타임 스탬프네트워크 카드의 맥어드레스 기반으로 생성한다.

      • 단조 증가하는데 7분 주기로 초기화 된다고 한다.

        • 7분 주기로 초기화되기에 장기적으로는 랜덤성을 유발한다.

      단조 증가?

      • 값이 지속적으로 같거나 증가하는 성질을 단조 증가라고 한다.

      • autoincrement 같은 설정이 단조 증가 값의 예시라고 볼 수 있다.

    • 버전 2

      • 잘 안씀

    • 버전 3

      • 이름과 네임스페이스 해시(MD5)

      • 고유 문자열로 부터 생성된다고 한다.

    • 버전 4

      • 순수 랜덤 생성이다.

      • 완전 랜덤임.

    • 버전 5

      • 이름과 네임스페이스 해시(SHA-1)

      • 고유 문자열로부터 생성된다.

UUID - B-Tree Index 문제점

  1. 본질적으로 UUID 는 랜덤 값이기에

    • B-Tree 구조에 비효율적이다.

  2. UUID 를 유니크 컬럼으로 사용하는 경우 MySQL 의 Change Buffer도 사용이 불가능하다.

    UUID 의 무작위성(Randomness) 로 인하여 인덱스의 높은 분산성이 발생한다.

    • Change Buffer 의 기본 원리부터 따지고 들면

      • InnoDB 스토리지 엔진의 경우 성능 향상을 위해 Change Buffer 라는 구조를 사용한다.

      • 변경 버퍼는

        • 세컨더리 인덱스(보조 인덱스) 에 대해 Insert, Update, Delete 작업을 하는 경우

        • 인덱스 변경을 곧바로 디스크에 반영하지 않고 메모리에 임시 저장했다가

        • 나중에 일괄적으로 처리(Batch Processing) 해서 디스크 접근 횟수를 줄이는 방식 이다.

      • 변경 버퍼는

        • 보조 인덱스 에만 적용이 가능하다.

        • 클러스터드 인덱스(PK) 에는 적용되지 않는다.

    • Change Buffer 사용 조건

      • 효율적으로 동작하려면

      • 보조 인덱스에 삽입할 데이터들이 국지적으로 + 집중적으로 배치되어 있어야 한다

        • 변경되는 데이터들이 특정 페이지(Page) 에 밀집된 형태로 변경이 발생해야 메모리에서 다량의 변경을 일괄 처리함으로써 디스크 접근 횟수를 현저히 줄일 수 있음.

    • 왜 문제가 되냐?

      • UUID 의 분산성때문에

        • UUID 삽입시 마다 무작위한 위치의 인덱스 페이지 에 접근해야 한다.

        • 매번 인덱스 페이지를 디스크에서 로드 OR 업데이트 해야하는 상황이 발생한다.

        • 디스크 I/O 비용이 증가해 .. 변경 버퍼의 장점을 누릴 수 없고

        • 성능의 저하가 발생한다.

  3. UUID 를 PK 로 설정하면 보조 인덱스 비대화가 발생하여 성능이 저하된다.

    • 위 주석 참고

  4. 최근 데이터 위주의 위킹셋 특성과 맞지 않는다

    1. 인덱스 워킹셋 크기 증가로 메모리의 효율이 감소한다.

    2. 디스크 IO 가 증대된다.

UUID 컬럼 길이 문제

  • 16바이트 이진 값이지만, 실제로 32바이트 문자열로 저장하는 경우가 많다

  • 컬럼 길이로 인하여 메모리와 인덱스 공간 차지가 증가된다.

비교(1억건 테이블 기준)

  • 8바이트 정수 PK ; 약 6GB

  • 32바이트 문자열 PK ; 약 24GB

  • 보조 인덱스도 커지면서 전체적인 인덱스 크기가 급증한다.

  • AWS 인스턴스 기준으로 최대 18,000$ 정도의 월 비용 차이가 발생한다고 한다.

UUID 대안

  • Auto Increment

    • 단조 값이지만, 외부 노출시 문제가 있다

  • Snowflake / Sonyflake

    • 분산 시스템에서 중복되지 않는 고유 ID 를 생성하는 방식 중에 하나이다.

    • 구성 3요소

      1. 타임 스탬프

        1. 과거 특정 시점(보통 서비스 시작일) 기준으로 한 경과 시간을 밀리초(ms) 단위로 표현한다.

        2. 시간이 흐름에 따라 숫자가 점점 커진다.

          1. 단조 값을 가질 수 있다는 장점이 있다.

      2. 머신 노드 ID

        1. 분산 시스템에서 여러 서버(노드) 가 동시에 ID 를 생성한다

        2. 서로 다른 서버가 동시에 같은 타임스탬프에 ID 를 생성하더라도 서버 간 충돌을 방지 할 수 있다.

        3. 예시

          • 서버 1: 001

          • 서버 2: 010

          • 서버 3: 011

          • 이런식으로 서버별 머신 ID 를 부여할 수 있음.

      3. 시퀀스 번호

        • 같은 서버에서 같은 밀리초(ms) 에 여러 개의 ID 가 발급될 수 있기에

        • 단조증가하는 시퀀스 번호를 추가하여 충돌 방지함.

        • 같은 서버에서 1234ms 의 타임스탬프에 3개의 ID 가 필요한 경우

          • 1,234 ms | 001 | 0001

          • 1,234 ms | 001 | 0002

          • 1,234 ms | 001 | 0003

Real MySql 저자가 추천하는 데이터 모델링 방법

  • UUID 의 필요성에 대해 검토해라

  • 내부적인 식별자는 auto increment 나 Snowflake / Sonyflake 를 사용해라

  • UUID 가 필수인 경우에는 PK 로 사용하지말고

    • 별도의 컬럼으로 사용해서 테이블 성능을 유지하도록 해라.







- 컬렉션 아티클