Backend/MySQL

자주 바뀌는 데이터, 정적 테이블에 넣어도 괜찮을까

동구름이 2025. 6. 5. 21:58

문제 상황

서버가 사용자의 위치 정보를 지속적으로 추적하고 관리해야 하는 요구사항이 주어졌다.

 

그리고 고려해야할 조건은 아래와 같다.

 

1. 위치 정보는 매우 자주 바뀐다. 서비스 특성상 5~30초 주기로 위치 갱신 발생

2. users 테이블은 비교적 정적이다 닉네임, 프로필 사진, 이메일 등은 변경이 거의 없음

3. 서버에서 위치 정보를 관리해야하는 서비스다.

 

 

ERD를 설계하는데 문득 "사용자의 위도/경도 위치 정보를 정적인 users 테이블에 넣는 게 맞을까?" 생각이 들었다.

한 테이블에 다 넣은 설계

 

어차피 사용자 정보인데 한 테이블에 있는 게 편하지 않나?

 

하지만 조금만 고민해보면, 이 결정은 단순한 편의성 이상의 영향을 끼친다. 

 

 

 

고려 사항 : 구조적 병목

놓치기 쉬운 RDB의 저장 방식이 있다. 바로 "디스크는 row가 아니라 블록(Page) 단위로 읽고 쓴다"는 점이다. 

 

 

RDB의 물리 구조 이해하기

 대부분의 RDBMS(PostgreSQL, MySQL 등)는 데이터를 8KB 단위의 '페이지(Page)' 블록으로 저장한다.

 

하나의 페이지는 아래처럼 여러 row를 묶어서 디스크에 배치한다.

[ Page 101 ]
┌──────────────────────────────────────┐
│ User 1 (nickname, email, lat/lng...) │
│ User 2 (...)                         │
│ ...                                  │
└──────────────────────────────────────┘

 

즉, DB는 특정 row 하나만 읽거나 수정하더라도, 해당 row가 속한 페이지 전체를 로딩하고 수정한 뒤 다시 저장해야 한다.

 

그런데 위치 정보는 자주 바뀐다 

예를 들어 사용자 위치가 10초마다 업데이트된다고 해보자.

UPDATE users SET latitude = ?, longitude = ? WHERE id = ?

 

이 쿼리는 단순히 위치 필드만 바꾸는 것처럼 보이지만, 실제로는 다음과 비효율이 발생한다.

 

 

디스크 I/O 병목

위치가 들어있는 row는 페이지 101에 있다.

→ UPDATE가 발생하면 페이지 101 전체가 디스크에서 읽혀지고, 다시 덮어써진다

→ nickname, email 같은 안 바뀌는 정보까지 포함된 페이지가 자주 교체된다.

 

즉, 단 두 필드를 수정했을 뿐인데도, 해당 페이지 전체가 계속 읽히고 다시 저장되는 반복 작업이 발생한다. 

그리고 이 페이지에는 nickname, email처럼 바뀌지 않는 정보도 포함되어 있다.

 

결국 위치 정보 하나 바뀔 때마다, 정적 데이터가 들어있는 블록까지 강제로 I/O 연산 대상이 된다.

 

캐시 오염

DB는 자주 쓰는 페이지를 메모리에 캐시(Buffer Pool)해둔다.

 

하지만 위치 정보가 자주 바뀌는 페이지는 다음과 같은 흐름을 겪는다

1. 위치 정보가 갱신되면 해당 페이지는 dirty 상태가 된다.

2. 일정 시점이 되면 해당 페이지는 디스크에 flush 된다.

3. 그 과정에서 페이지는 캐시에서 evict 될 수 있다.

4. 다시 같은 사용자 정보를 조회하면 → 디스크에서 페이지를 재로드해야 한다.

 

→ 즉, 자주 바뀌는 필드 하나 때문에 같은 페이지에 있는 정적 정보도 자주 캐시에서 밀려나고 다시 불려온다.

 

결과적으로 nickname, email 같은 자주 쓰는 정적 필드의 캐시 히트율이 급격히 떨어진다.

 

락 충돌 증가

다음 두 트랜잭션이 동시에 발생한다고 해보자

 

A 트랜잭션: 닉네임 변경

B 트랜잭션: 위치 정보 업데이트 (10초마다)

 

하지만 이 둘은 같은 row 혹은 같은 페이지에 있다. 그래서 DB는 락을 걸어야 하므로 충돌이 발생한다.

 

 

해결책: 테이블 분리

위치 정보만 따로 분리한다면 어떻게 될까?

 

1. users 테이블은 거의 읽기 전용 

닉네임, 이메일 등은 자주 변경되지 않으니 캐시에 안정적으로 유지 가능하다.

 

2. user_locations 테이블은 쓰기 전용

위치 정보만 빠르게 갱신한다. 디스크/메모리도 여기에 집중될 수 있다.

 

3. 두 테이블은 서로 다른 페이지 공간에 저장된다.

users와 user_locations는 서로 다른 테이블이므로 디스크 상에서도 완전히 다른 블록(Page) 단위 공간을 사용한다.

결과적으로 I/O, 캐시, 락이 모두 분리된다.

 

 

결론

자주 바뀌는 필드는 그것만으로도 디스크, 캐시, 트랜잭션 전체에 영향을 미친다.

위치처럼 자주 바뀌는 데이터는 성능과 확장성을 고려해 분리하는 것이 좋다.