서비스 개편시 PostgreSQL 도입기
배민스토어 셀러개발팀 진소린, 김태정
1
서비스 소개
2
목차
- 우리 서비스에서 도입 배경
- 활용 사례
3
(구) 배민스토어 역사
4
예전에 우리 서비스는요…
배민 내 커머스 서비스에 결합된 부가적인 서비스
참고: MySQL 5.7
모놀리식 구조
5
우리가 했던 목표는
“셀러가 판매를 더 잘 할 수 있게”
다른 서비스와 독립적인 서비스 개발
6
7
개발자들의 고민
OOP ? Relational?
다중 값 속성
OOP ? Relational?
8
OOP ? Relational?
다중 값 속성(C,S,V)
9
CREATE TABLE product (
id bigint PRIMARY KEY,
search_tag_csv varchar(200)
);
INSERT INTO product VALUES
(1, '견과류,견과,건과일,건과');
@Column(name = "search_tag_csv")
String searchTag;
List<String> getSearchTag() {
return
List.of(searchTagCsv.split(","));
}
OOP ? Relational?
다중 값 속성(Mapping Table)
10
CREATE TABLE product (
id bigint PRIMARY KEY,
// …
);
CREATE TABLE product_search_tags (
product_id bigint,
search_tag varchar(20),
);
@ElementCollection
@CollectionTable(
name = "product_search_tags",
joinColumns = @JoinColumn(name =
"product_id"))
@Column(name = "search_tag")
List<String> searchTag;
OOP ? Relational?
다중 값 속성(PG배열)
11
CREATE TABLE product (
id bigint PRIMARY KEY,
search_tag varchar(20)[10],
// …
);
INSERT INTO product VALUES (1,
'따앙콩', 100,
ARRAY['견과류','견과','건과일','건과
','하루견과','견과믹스']
);
import
org.hibernate.annotations.Type;
@Column(name = "search_tag")
@Type(type = "list-array")
List<String> searchTag;
// hibernate-types 라이브러리 사용
• 스펙: 상점은 공동대표자가 될 수 있다
• N>10 인 경우는 없다
• 고민
• 일정 촉박
• 어떻게 간단하게 모델링 할까?
12
객체 속성
객체 속성(Mapping Table)
13
CREATE TABLE shop (
id bigint PRIMARY KEY,
// …
);
CREATE TABLE shop_owner (
shop_id bigint,
name varchar(20)
);
@ElementCollection
@CollectionTable(
name = “shop_owner",
joinColumns = @JoinColumn(name =
“shop_id"))
List<ShopOwner> owners;
객체 속성(Mapping Table)
14
가게id 성명 생년월일
2 이나영 1980-01-01
2 김태정 1999-01-01
2 진소린 2000-01-01
Id 상호명
1 우아한형제들
2 나영커피
3 냠냠
가게 테이블
대표자 테이블
객체 속성(PG JSONB)
15
CREATE TABLE shop (
id bigint PRIMARY KEY,
owner jsonb,
);
import org.hibernate.annotations.Type;
@Column(name = "owner")
@Type(type = "jsonb")
List<ShopOwner> owners;
class ShopOwner {
String name;
LocalDate birthday;
}
그 외 타입들
• 범위 (Range)
• timestamp with time zone range -> Range<Instant>
• 시작일시 ~ 종료일시를 한 컬럼으로 표현할 때 유용
16
가공 및 인덱싱 가능
varchar[], tstzrange, jsonb, ...
17
결과
PostgreSQL의 다양한 기능을 활용하여
Impedance mismatch 감소
개발 기간 단축
18
업무에서 PostgreSQL 활용 사례
19
Schema : 연관 테이블 그룹핑
20
연관 테이블 그룹핑
Cluster
Database
Table
Schema
21
AWS RDS Cluster
단일 DB
도메인: 주문, 상품, 가게, 정산…
주문
상품
가게
정산
연관 테이블 그룹핑
Cluster
Table
Schema
22
AWS RDS Cluster
도메인: 주문, 상품, 가게, 정산…
주문
상품
가게
정산
Database
개발자 A
공통DB
(개발환경) 개발자 별로 개인 DB
22
DB 권한 관리
23
DB객체
상품
옵션
주문
결제
주문/결제 사용자
상품개발자 주문개발자 QA
24
QA 김태정, QA 진소린
김태정
진소린
User
CRUD Read(Select)
UPDATE
특정 컬럼
CRUD
Role/Group(권한)
(우리가) 자주 사용하는 운영 쿼리
25
운영쿼리 - Returning #1
UPDATE users
SET firstname = 'Rin'
WHERE lastname = 'Jin'
RETURNING *
26
UPDATE users
SET firstname = 'Rin'
WHERE lastname = 'Jin'
SELECT *
FROM users
WHERE lastname = 'Jin'
운영쿼리 - Returning #2
UPDATE users t
SET firstname = 'Rin'
FROM users old
WHERE t.id = old.id AND t.lastname = 'Jin'
RETURNING t.id, old.firstname old_value, t.firstname new_value
27
28
운영쿼리 - 데이터 백업 후 삭제
WITH deleted AS (
DELETE FROM users
WHERE lastname = 'Kim'
RETURNING *
)
INSERT INTO users_backup
SELECT *
FROM deleted
RETURNING *
변경된 데이터를 즉시 눈으로 검증 가능함
만약 문제가 발생하면 준비해 둔 복원 쿼리로 백업 테이블에서 복원이 가능함
자주 변경되는 운영 테이블에 트랜잭션을 걸고 작업하지 않아도 됨
29
운영쿼리 - 데이터 백업 후 삭제
운영쿼리 - 더미 데이터 생성하기
30
generate_series (start T, stop T [, step T ]) " setof T
운영쿼리 - 더미 데이터 생성하기
31
SELECT generate_series(1, 10);
운영쿼리 - 더미 데이터 생성하기
32
INSERT INTO users (id, firstname, lastname)
SELECT u.id + s id,
u.firstname || '#' || s,
u.lastname || '#' || s * 3
FROM users u,
generate_series(100, 200, 2) s;
33
http://bit.ly/3fZ058g
끝!

[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정