본문 바로가기
DB/RDB

UUID for Primary Key

by devson 2021. 7. 23.

왜 UUID를 Primary Key로 쓸까?

DB에서 Primary Key를 사용할 때 단순하게 Sequence(Auto Increment)를 사용할 수 있다.

하지만 소셜 서비스에서 주로 사용되는 username과 같이 PK와 별개로 특정 유저를 특정하는 값이 존재하지 않고 외부에 Table의 PK(ID) 값을 노출한다고 하였을 때, Sequence(Auto Increment) 값을 사용하는 것은 단순 증가 값이기 때문에 본인 것이 아닌 데이터에 접근할 수 있는 ID 값을 외부에 노출하는 것과 같다고 볼 수 있다.

 

그래서 DB에서 Primary Key를 사용할 때 다른 데이터에 쉽게 접근할 수 있는 ID 값을 쉽게 유추할 수 없도록 UUID를 사용할 수 있다.

UUID v4 같은 경우 랜덤하게 생성되고 확률상으로는 100%는 아니지만 실질적으로는 값이 충돌하는 경우가 없다고 봐도 무방하다고 본다.

(방어적으로 개발한다면 충돌을 고려할 순 있지만 아직은 그런 케이스를 겪어본적은 없다)

UUID를 Primary Key로 썼을 때 성능 이슈와 솔루션

Data Size

MySQL을 기준으로 BIGINT의 경우 8-bytes 이다.

UUID는 CHAR로 처리할 경우 36-bytes 이다.

기본적으로 UUID를 쓴다면 그만큼 데이터가 더 필요하다는 것을 의미한다.

솔루션

UUID_TO_BIN or UNHEX를 사용하여 BINARY로 처리할 경우 16-bytes로도 처리가 가능하다.

물론 BIGINT로 처리하는 것에 비해 데이터가 크긴하지만 CHAR를 사용했을 때 보다 데이터를 절반 이상으로 줄일 수 있다.

다만 SELECT 를 통해서 확인할 때는 binary 값이므로 사람이 읽을 수 있도록 값을 변환하는 과정이 필요할 수 있다.

 

Indexing

UUID v4 같은 경우 unique 할진 몰라도 랜덤값이기 때문에 DB 입장에서는 insertion 되는 값이 순서가 없이 무작위 값이 들어오기 때문에 이를 정렬하는데 큰 부담이 된다.

(기본적으로 Primary Key는 Clustered Index로 사용되기 때문에 indexing의 대상이다)

 

특히나 테이블의 데이터 양이 많고 새로 쌓이는 데이터도 많을 때 indexing으로 인해 DB의 성능이 저하될 수 있다.

 

출처 https://blog.programster.org/mysql-performance-when-using-uuid-for-primary-key

솔루션

index와 관련하여 PK로써 UUID를 효과적으로 사용하는 방법은 어떤것이 있을까?

여러 방법이 있겠지만 쉽고 빠르게 적용할 수 있는 것 중 하나는 UUID를 랜덤하게 생성하되 이 값을 sequencial 하게 생성하는 것이다.

값이 sequencial하게 들어오니 DB 입장에서 새로운 데이터가 들어오더라도 indexing으로 인해 드는 리소스가 랜덤값보다 현저하게 줄 것이다.

 

출처 https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/

 

Sequencial UUID를 생성하기 위한 방법

  • MySQL function

MySQL의 function 기능을 통해 Sequencial UUID를 생성하는 function을 만들어 사용한다.

방식은 여러가지가 있으나 해당 글을 쓸 때 참고한 포스팅의 방식을 참고하였을 때 아래와 같은 결과를 확인할 수 있었다.

 

  • Java

Java Uuid Generator (JUG) 라는 Library가 있다.

JUG를 사용했을 때 아래와 같은 결과를 확인할 수 있었다.

 

  • Node.js

uuid-sequential 이라는 Libary가 있고, 이를 사용했을 때 아래와 같은 결과를 확인할 수 있었다.

 


 

References

댓글