왜 DB 테이블 파티셔닝을 도입했나
프롭테크 회사에서 부동산 중개사들이 사용하는 솔루션, 내부 부동산 투자 개발팀이 사용하는 솔루션을 만들고 운영주입니다. 이러한 솔루션을 위해 부동산 공공데이터 베이스를 구축, 운영중인데 아직 경험이 부족하여 더 나은 서비스를 제공하기 위해 DB 에 대해 공부하고 있습니다.
고작 1+a 년동안 부동산 데이터를 다룬 제가 파악한 특성은 (1) 데이터 양(Volume)이 많다, (2) 그렇게 양이 많은 데이터가 다양하다는 점입니다.
얼핏보면 빅데이터의 3V(Volume, Velocty, Variety) 가 생각나는 특징이죠? 하지만 엄연히 말하자면 다릅니다. 양이 많은 것은 맞지만 TB 단위로 많은 것은 또 아니고, 다양하지만 데이터의 형태(정형, 반정형, 비정형) 가 다양한것이 아니라 관점(건축물대장, 토지특성정보 등)이 다양한 것이기 부동산 데이터란 양이 좀 많은(~800GB) 정형데이터 뭉치인 VLDB(Very Large DBMS) 라고 말할 수 있습니다.
(경험이 깊으신분들의 관점은 다를 수 있습니다.)
그리고 이 VLDB 는 (1) 매달 bulk data 삽입을 필요로 하고, (2) 하나의 큰 테이블(~3억건의 데이터) 데이터를 조회해야하는 이슈가 있습니다. 이 이슈를 어떻게 해소할지 알아봤고 저는 테이블 파티셔닝을 통해 이슈를 해소할 수 있을 것이라는 가설을 세웠습니다.
그래서 24년에 건축물대장, 토지특성정보를 업데이트(Bulk Insert)하면서 데이터베이스 파티셔닝을 도입하기로 하였습니다.
테이블 파티셔닝은 어떤 이득을 주나
위에서 데이터베이스 테이블 파티셔닝을 통해 삽입과 조회 성능을 모두 향상시킬 수 있을것이라는 가설을 세웠다고 말했습니다.
어떤 근거를 가지고 이러한 가설을 세우게 되었는지 알기 위헤서는 테이블 파티셔닝에 대한 이론적인 이야기를 해야합니다.
테이블 파티셔닝이란?
우선 테이블 파티셔닝이 무엇인지 알아야겠지요.
일반적인 RDBMS 는 데이터베이스라는 하나의 인스턴스 안에서 데이터를 테이블이라는 "하나의 물리적 집합"으로 관리합니다.
이러한 물리적 집합을 "작은 논리적 부분집합"으로 나누어 관리하는 것을 테이블을 파티셔닝이라고 합니다.
파티셔닝의 이득
큰 물리적 집합을 작은 논리적 부분 집합으로 나누면 어떤 이득이 있을까요?
테이블의 사이즈가 커지면 조회속도가 느려집니다. 그렇기 때문에 우리 개발자들은 테이블에 색인(Index) 를 생성해서 조회속도를 향상시키죠. 하지만 테이블이 굉장히 커진다면 아무리 색인을 잘 걸어둬도 색인의 크기도 커지기 때문에 점점 조회 속도가 느려질 수 밖에 없습니다. 게다가 색인이 커진다면 새로운 데이터를 삽입할때 인덱스를 거는 작업의 속도도 느려져서 데이터 삽입 속도도 느려지겠죠.
테이블 크기에 따라 색인을 통해 얻을 수 있는 성능상 이점이 점진적으로 체감하다 못해 종국에는 데이터 삽입 성능이 감소하는 현상을 마주할 수 있습니다. 그렇다면 이 문제의 원인이 되는 테이블의 크기 자체를, 색인의를 작게 나눈다면 우리는 색인이 가져다주는 이점을 더 큰 데이터셋에 대해서도 누릴 수 있지 않을까요?
물리적인 테이블은 하나지만 DBMS 가 접근하는 논리적인 단위를 잘게 나눠서 조회, 삽입 성능상 이점을 가져가도록 만들어주는 것이 테이블 파티셔닝입니다.
파티셔닝 주의점
위의 파티셔닝이 가져다주는 이점을 봤을땐 무조건 파티셔닝을 하는게 좋은게 아닌가하는 의문이 들었습니다. 하지만 우리가 고려하는 기술들 중에서 무조건 나쁘거나 무조건 좋은건 없죠. 비용과 편익 사이에서 Trade off 가 발생하기 마련입니다.
파티셔닝을 적용할때 다음의 비용을 고려해야 합니다.
(1) 쿼리 플래너 오버헤드
위에서 계속 물리적인 테이블을 "논리적" 으로 작은 단위로 나눈다고 계속 이야기하고 있습니다. 이렇게 논리적으로 나눠진 파티션에 대한 접근을 DB 사용자 혹은 서버가 크게 신경쓰지 않아도 되는 이유는 우리의 고마운 친구 쿼리 플래너가 알아서 파티션이 나눠진 곳에 알아서 접근해줍니다. 그리고 이 과정에서 어떠한 작업이 있을것이라고 예상할 수 있죠. 그리고 이 작업이 추가된만큼 쿼리 플래너가 쿼리 플랜을 만드는데 조금 더 시간이 걸리게 됩니다.
만약 테이블 크기가 크지 않아서 만족스러운 성능이 나오는데, 더 욕심을 부려서 파티셔닝을 적용하고 싶은거라면 다시 생각해봐야겠죠?
(2) 추가적인 설계, 관리 비용 발생
우선 테이블 파티셔닝의 이점을 얻기 위해서는 설계 및 관리 리소스가 들어갑니다.
파티셔닝의 이득을 극대화하기 위해서는 실제 데이터 삽입, 조회 패턴에 따라 테이블을 논리적으로 잘 분리해둬야합니다. 이러한 실제 사용 패턴을 고려하지 않고 파티셔닝을 한다면 하나의 조회 트랜잭션 안에서 다수의 파티션을 조회(Cross-Partition Queries)해야하거나, 삽입 트랜잭션 안에서 다수의 테이블에 삽입을 해야해서 이득을 약화시키거나 오버헤드로 인해 오히려 성능이 저하되는 부작용이 발생할 수 있습니다.
쿼리를 작성할때 항상 파티션을 염두해야합니다. 파티션 제약조건을 WHERE 절에 걸어두지 않거나, 테이블 이름 자체를 명시하지 않는다면 파티션을 적용한 이유가 없겠죠. 결국 파티션을 함으로써 얻는 이득이 있지만 그 이득을 얻기 위해서는 파티셔닝 설계와 쿼리 작성시 더욱 주의를 기울여야합니다.
또한 파티셔닝된 테이블에는 PRIMARY KEY Constraint 를 직접적으로 사용할 수 없습니다. 이것이 시사하는 점은 Unique Key를 임의로 관리해야한다는 사실입니다. 이것 역시 개발자가 신경써줘야하는 요소이지요.
실제로 어떻게 적용하였나
파티셔닝 적용 기준
파티셔닝을 도입한 데이터베이스는 제가 쓰고있는 PostgreSQL 버전 15입니다.
부동산 중개 솔루션, 투자 개발 솔루션에서 접근하는 부동산 데이터의 패턴은 주로 지역기반이었습니다. 그리고 하나의 트랜잭션 안에서 함께 조회하는 데이터들은 시도(서울시, 경기도, 부산광역시 등) 단위 안에서 일어났습니다. 이러한 사실에 기반하여 저는 테이블을 "시도"라는 논리적 단위로 분리하였습니다.
다만 데이터 건수가 1천만건 이상인 테이블에 대해서만 적용하였는데요.
1천만건 이하의 테이블에서 데이터를 조회, 삽입하는 것은 큰 무리가 없을 것이라는 생각이 있었고, 파티셔닝을 적용하는 것은 관리 리소스가 증가하는 것이기 때문에 비용~편익 비교 관점에서 임의로 기준을 설정한 것입니다.
(앞으로 계속 API 서버, 데이터베이스를 운영하면서 지켜보면서 더 최적의 조합이 있다면 그에 맞게 변경시킬 예정입니다.)
다만 시도 별로 데이터를 나누면 data skew 문제가 발생하지만 부동산 데이터에서는 어쩔 수 없는 문제라고 생각했고, 이미 데이터 접근 패턴을 분석했기 때문에 대부분의 경우 data skew 가 큰 문제가 되지 않을 것이라는 확신이 있었습니다.
PostgreSQL 에 파티셔닝 적용하기
공식문서(Link) 를 보고 공부한 결과 PostgreSQL 는 Range, List, Hash 라는 파티셔닝 방법을 제공하고 있습니다. 특정 값(시도) 에 의해 파티셔닝을 하는 저의 요구사항에는 List partitioning 이 적합한 방법이었습니다.
생성된 물리적 테이블에 논리적 하위 파티션을 붙이고, Insert 자체는 물리적 테이블에 하면 DBMS 가 자동으로 파티션에 맞게 분리해서 데이터를 넣어줍니다.
저같은 경우는 부동산 데이터 파일을 내려받은 후 파이썬 코드를 통해 각 시도마다 분리하여 파일에 넣고 copy 명령어로 별도로 테이블에 넣었습니다. 데이터 정제, 처리 코드도 많은 공을 들인만큼 같이 공유하고 싶은데 회사에서 데이터 관련된 사항은 민감해서 충분히 추상화시킨 뒤 공개할 예정입니다.
ORM 과 파티셔닝
JPA 를 사용중입니다. 저는 JPA 에 연동된 엔티티가 파티셔닝되어 있다면 hibernate 가 만드는 쿼리가 자동으로 파티션에 최적화되어서 만들어질줄 알았습니다. 하지만 그렇지 않더군요. 직접 쿼리문을 조작해서 파티셔닝에 최적화되도록 만들어줘야 했습니다.
그리고 실제 생성되는 쿼리문에 맞게끔 파티셔닝 조건을 바꾸는 과정도 있었습니다.
예를 들어 PostgreSQL 에서 제공해주는 TEXT 조작 함수인 LEFT 를 이용해서 파티셔닝을 했지만 hibernate 가 생성해서 날리는 쿼리는 substr 을 이용하고 있었습니다. 이러한 이유로 ORM 을 통해 생성된 쿼리가 정말 파티션에 최적화된 것인지 확신할 수 없었죠. ORM 에서 날아가는 쿼리를 모두 native 로 모두 바꿔서 보낼게 아니라면 차라리 DBMS 의 파티셔닝 조건을 substr 로 바꾸는게 안전하다고 판단하여 파티션 작업을 다시 진행했습니다.
ORM 을 쓰신다면 이러한 조건을 따져보시기 바랍니다.
실제로 어떤 이득을 보았나
실제 쿼리 조회 성능은 10% 이상 향상되었습니다. 그리고 대용량 삽입(Bulk Insert) 시간도 크게 줄일 수 있었죠. 이것만으로도 뿌듯한 일이었는데 더 큰 이득을 본 사건이 있었습니다.
바로 24년 1월에 있었던 2건의 법정동 개편, 경기도 부천시에 '구' 단위 행정구역이 다시 부활했고 전라북도가 전북특별자치도로 개편되는 사건이었습니다. 이러한 개편에 대해서는 정부가 변경된 데이터를 내놓을때까지 기다리는 서비스가 많았지만 전문가가 사용하는 솔루션에서 이런 변화를 바로 적용하지 못하면 신뢰를 잃는다고 생각했습니다.
이에 직접 행정안전부에서 변경 사항을 파악하고 DB 에 적용할 수 있는 방법을 연구해서 다른 소비자향 프롭테크 서비스보다 더 빠르게 법정동 개편 이슈에 대응할 수 있었습니다. 이때 시도 단위로 파티션을 나눠놓은게 큰 도움이 되었는데요. 아예 시도 단위로 분리되어있던 전라북도 이슈는 말할것도 없고, 부천시 이슈도 경기도 데이터셋에서만 조작을 하면돼서 더욱 빠르게 적용할 수 있었습니다.
테이블 파티션을 통해 성능적인 이점을 챙겼을 뿐만 아니라 데이터 관리면에서도 이점이 있다는 것을 확인할 수 있었습니다. 다들 즐거운 파티셔닝하세요!
'탐구 생활 > 개발 탐구' 카테고리의 다른 글
SQLAlchemy read-only session (0) | 2025.02.22 |
---|---|
티스토리 스킨 hELLO 에 기여해보기 (0) | 2025.02.19 |
FastAPI & Postgres 로 multi-tenancy 구현하기 (0) | 2025.02.17 |
Java, SpringBoot 에서 Geometry 좌표 핸들링 (2) | 2024.02.09 |
AWS AutoScaling 수평 확장시 어플리케이션 자동 세팅 (2) | 2024.02.09 |