테이블의 기본키로 UUID를 사용하는 방법은 3가지 이점이 있다.
이러한 전제가 있으면, 서로 다른 테이블에서 관리되던 데이터를 하나의 데이터 소스로 합치기 쉽다.
예를 들어, 뉴스 콘텐츠 테이블이 1개가 있고, 이를 검색 엔진 (ElasticSearch)에 복제하고 있다고 가정해보자. 이후, 잡지 콘텐츠 테이블이 필요하게 되어, 이 정보를 동일한 ElasticSearch에 추가해야하는 상황이 왔다고 상상해보자. 두 테이블이 숫자 기반의 pk를 사용하고 있었다면 두 콘텐츠의 ID가 충돌나는 현상이 발생하게 된다. 이 때문에 두 테이블을 하나의 소스에 합치기 어려워진다.
increment pk는 식별키값이 외부에 노출되기 쉽다. 그래서 의도하지 않은 사용자에게 데이터가 노출될 위험이 있다. 예를 들어, 회원 정보를 increment pk로 조회하는 API가 /user/{pk}/ 같은 URL 패턴이라면, pk를 증분하면 다른 고객의 정보가 쉽게 노출될 수 있다는 리스크가 있다. 그래서 봇이 URL을 스캔해 데이터가 유출될 가능성이 있다.
그리고 increment pk로 데이터의 수를 유추할 수 있기 때문에, 비즈니스 적으로 의미있는 수치가 외부에 노출될 가능성이 있다. 예를 들어 주문, 상품 테이블의 식별값이 increment pk로 사용된다면, 외부에 누적 주문수와 상품수가 노출될 수 있다.
uuid는 stateless하기 때문에 함수를 사용하여 키를 생성할 수 있다. 반면 increment pk는 데이터베이스를 조회해야지만 유니크한 키를 알 수 있다. 그래서 insert query를 호출하기 전에 매번 increment pk를 구하는 쿼리를 db에 요청해야한다. 만약 분산 데이터베이스를 사용하고 있다면, increment pk를 구하는 작업이 SPOF (single-point-of-failure)를 발생시킬 수도 있다.
uuid는 이러한 과정을 생략할 수 있어서 성능상 이점이 있다.
그래도 기본키로 UUID를 사용하면 안되는 이유
이렇게 보면 pk 식별자로 increment pk가 아니라 UUID를 사용하는 것이 무조건 좋아보인다.
그러나 UUID는 increment pk 보다 더 많은 저장 장소를 필요로한다. 그리고 관계 테이블에서 외래키로 uuid를 사용한다면, 더 많은 저장 장소를 사용하게 된다. 이 경우, 테이블과 인덱스 크기가 커져서, 데이터베이스의 디스크와 메모리를 많이 사용하게 된다.
테이블의 기본키는 외부에 노출되면 안된다.
데이터의 기본키는 외부에 노출되면 안된다. increment pk, uuid 모두 상관없이 그러하다.
pk를 변경하는 비용은 높다. pk는 언젠가 변경될 수 있기 때문에, 기본키를 외부에 노출하면 이 비용은 더 높아진다.
예를 들어, 기본키가 변경되면, 외부에 공개되었던 페이지의 데이터가 조회되지 않는 현상이 발생할 수 있다.
시스템에서 절대 변경되지 않는 것은 없다. 예를 들어, 데이터가 많아져서 저장소를 RDB에서 NoSQL으로 이전하게 되는 경우, pk가 숫자형에서 문자형으로 변경될 수 있다.