🐥 카카오테크캠퍼스 - 2단계 1주차 Entity 최종 설계
- 부족한 기능에 대한 요구사항을 미리 예상할 수 있는가?
- (예를 들면 상품등록 api가 기존 요구사항에는 없는데 추후 필요하지는 않을지, 이런 부분들을 생각하였는지)
- 요구사항에 맞는 API를 분석하고 사용자 시나리오를 설계하였는가?
- (예를 들어 배포된 서버와 화면 설계를 제시해줄 예정인데, 특정 버튼을 클릭했을 때 어떤 API가 호출되어야 할지를 아는지)
- 응답되는 데이터가 프론트앤드 화면에 모두 반영될 수 있는지를 체크하였는가?
- (예를 들어 배송관련 비용이 있는데, 이런것들이 API에는 없는데 이런 부분을 캐치할 수 있는지)
- 테이블 설계가 모든 API를 만족할 수 있게 나왔는가?
- (테이블이 효율적으로 나왔는가 보다는 해당 테이블로 요구사항을 만족할 수 있는지에 대한 여부만)
앞서 🐥 카카오테크캠퍼스 - 2단계 1주차 Entity 세부 설계에서 작성한 테이블을 토대로, 제약 조건 등을 설정하고 아래 요구사항을 만족시키자
전체 ER - Diagram
User(사용자)
{
"username" : "meta",
"email" : "meta@nate.com",
"password" : "meta1234!"
}
API 응답을 보면, username, email, password 필드가 필요합니다
User 테이블을 보면, 해당 서비스를 사용하는 모든 사용자를 말합니다.
Sudo Code
- id : PK
- userName : 유저 이름
- email : 이메일
- password : 비밀번호
- status : 관지라/일반 사용자
- createDate : 생성 날짜
- updateDate : 수정 날짜
SQL 쿼리
CREATE TABLE User (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
userName VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
status ENUM('NORMAL', 'ADMIN'),
createDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updateDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `email_UNIQUE` (`email`)
);
추가적인 테이블 : User History
사용자의 로그인과 로그아웃 등등을 기록하는 것 등의 로그를 남기는 것이 필요하다 생각했습니다
CREATE TABLE UserHistory (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
userId INT,
loginTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
logoutTime TIMESTAMP,
FOREIGN KEY (userId) REFERENCES User(id)
);
Product(상품)
{
"success": true,
"response": [
{
"id": 1,
"productName": "기본에 슬라이딩 지퍼백 크리스마스/플라워에디션 에디션 외 주방용품 특가전",
"description": "",
"image": "/images/1.jpg",
"price": 1000
},
{
"id": 2,
"productName": "[황금약단밤 골드]2022년산 햇밤 칼집밤700g외/군밤용/생율",
"description": "",
"image": "/images/2.jpg",
"price": 2000
},
],
"error": null
}
Sudo Code
- id : PK
- productName : 제품 명
- description : 제품 설명
- image : 제품 사진
- price : 제품 가격
- sale :
- starCount : 별점
- createDate : 생성 날짜
- updateDate : 수정 날짜
SQL 쿼리
CREATE TABLE Product (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
productName VARCHAR(255) NOT NULL,
description TEXT,
image VARCHAR(255),
price INT NOT NULL,
sale INT,
starCount DECIMAL(3,2),
createDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updateDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
할인 필드
전체 상품 목록 조회
-
- 개별 상품 상세 조회
전체 상품 목록 조회를 보면, 특별가 페이지가 있는데 상세 조회를 보면 Option들 중 가장 값이 낮은 Option의 값을 출력하는 것을 알 수 있다
즉 Prodcut 테이블의 Price는 Option 중 가장 낮은 값이며, 할인을 적용한다면, 전체 상품에 할인을 적용하고 Option으로 할인하는 정도를 뿌리면 될거라 생각했다
Option(옵션)
제품 상세 보기의 데이터 형식을 확인합시다
{
"success": true,
"response": {
"id": 1,
"productName": "기본에 슬라이딩 지퍼백 크리스마스/플라워에디션 에디션 외 주방용품 특가전",
"description": "",
"image": "/images/1.jpg",
"price": 1000,
"starCount": 5,
"options": [
{
"id": 1,
"optionName": "01. 슬라이딩 지퍼백 크리스마스에디션 4종",
"price": 10000
},
{
"id": 2,
"optionName": "02. 슬라이딩 지퍼백 플라워에디션 5종",
"price": 10900
},
{
"id": 3,
"optionName": "고무장갑 베이지 S(소형) 6팩",
"price": 9900
},
{
"id": 4,
"optionName": "뽑아쓰는 키친타올 130매 12팩",
"price": 16900
},
{
"id": 5,
"optionName": "2겹 식빵수세미 6매",
"price": 8900
}
]
},
"error": null
}
options를 보니, 아래와 같이 필요해보입니다
Sudo Code
- id : PK
- productId : FK -> Product.id
- optionName : 옵션 이름
- price : 옵션 가격
- createDate : 생성 날짜
- updateDate : 수정 날짜
SQL 쿼리
CREATE TABLE Option (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
productId BIGINT,
optionName VARCHAR(255) NOT NULL,
price INT NOT NULL,
createDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updateDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (productId) REFERENCES Product(id)
);
Cart (장바구니)
{
"success": true,
"response": {
"products": [
{
"id": 1,
"productName": "기본에 슬라이딩 지퍼백 크리스마스/플라워에디션 에디션 외 주방용품 특가전",
"carts": [
{
"id": 65,
"option": {
"id": 1,
"optionName": "01. 슬라이딩 지퍼백 크리스마스에디션 4종",
"price": 10000
},
"quantity": 5,
"price": 50000
},
{
"id": 66,
"option": {
"id": 2,
"optionName": "02. 슬라이딩 지퍼백 플라워에디션 5종",
"price": 10900
},
"quantity": 5,
"price": 54500
}
]
}
],
"totalPrice": 104500
},
"error": null
}
Sudo Code
- id : PK
- userId : FK -> User.id
- orderItem : FK -> Item.id
- totalPrice : 장바구니 가격
- quantity : 장바구니에 들어간 갯수
- createDate : 생성 날짜
- updateDate : 수정 날짜
SQL 쿼리
CREATE TABLE cart (
id BIGINT PRIMARY KEY,
userId BIGINT NOT NULL,
optionId BIGINT,
totalPrice BIGINT,
quantity INT,
createDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updateDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (userId) REFERENCES User(id),
FOREIGN KEY (optionId) REFERENCES Option(id)
);
Order(주문)
{
"success": true,
"response": {
"products": [
{
"productName": "기본에 슬라이딩 지퍼백 크리스마스/플라워에디션 에디션 외 주방용품 특가전",
"items": [
{
"id": 65,
"option": {
"id": 1,
"optionName": "01. 슬라이딩 지퍼백 크리스마스에디션 4종",
"price": 10000
},
"quantity": 5,
"price": 50000
}
],
},
{
"productName": "삼성전자 JBL JR310 외 어린이용/성인용 헤드셋 3종!",
"items": [
{
"id": 3,
"option": {
"id": 1,
"optionName": "JR310BT (무선 전용) - 레드",
"price": 10000
},
"quantity": 5,
"price": 50000
}
],
}
],
"totalPrice": 104500
},
"error": null
}
Sudo Code
- id : 주문 번호(PK)
- userId : FK -> User.id
- totalPrice : 장바구니 가격
- createDate : 생성 날짜
- updateDate : 수정 날짜
생각해보니, Item Id가 없어도, userid로 cart를 조회하면 내가 구매할 상품들을 가져 올 수 있으니까
userId만 가지고 있으면 된다
SQL 쿼리
CREATE TABLE `order` (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
userId BIGINT,
orderItem BIGINT,
totalPrice BIGINT,
createDate DATETIME,
updateDate DATETIME,
FOREIGN KEY (userId) REFERENCES User(id),
);
Item(주문 아이템)
위의 주문 Item 필드를 확인하면 아래와 같은 데이터가 필요합니다
Sudo Code
- id : PK
- orderId : FK -> Order.id : 주문 번호
- optionId : FK -> Option.id
- quantity : 옵션 갯수
- price : 가격
- createDate : 생성 날짜
- updateDate : 수정 날짜
Product Id를 지운 이유는 option Table을 참조하는데 option table에 productId가 있어서 item을 unique하게 구분 할 수 있기 때문입니다
SQL 쿼리
CREATE TABLE item (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
orderId BIGINT NOT NULL,
optionId BIGINT NOT NULL,
quantity INT NOT NULL,
createDate DATETIME NOT NULL,
updateDate DATETIME NOT NULL,
FOREIGN KEY (orderId) REFERENCES `order`(id),
FOREIGN KEY (optionId) REFERENCES `option`(id)
);
질문
- 정규화를 어느 정도해야 읽기 성능과 쓰기 성능의
Tradeoff
를 적절히 조절할 수 있는가- 3단계 정도
- JOIN vs FK
Order 테이블과 item 테이블을 사용 할 때 FK(외래 키)와 JOIN 후 조회를 하는 것중 어떤게 더 효율적인가- 여러 테이블에 있는 데이터를 1번에 조회 한다던가 여러테이블의 다수의 조건을 통해 조회하는 경우 JOIN을 사용 합니다.
- FK를 사용하지 않는 경우는 DB에서는 실제로 연관관계를 맺지 않고 있기 떄문에 비지니스 로직에서 검증이 필요합니다.
- FK가 맺어져 있는 경우 데이터 삭제등 제약조건이 있어서 실제 서비스에서는 FK는 맺지 않고 사용하기도 합니다.
- 만약 비밀번호 필드가 8글자이하의 조건이 있다면, 추후 비즈니스 변경을 염두에 두고 varchar(255)로 설정을 해야할까요? 아니면 varchar(8)로 설정을 해야할까요?
- 일단은 비즈니스 변경을 염두에 두고 여유롭게 하는게 맞고, 데이터베이스 스키마도 인프라이기에 비지니스 로직이 담기면 안된다.
- 8글자 조건 설정은 에플리케이션에서 설정
- 예를 들어서 상품 가격 같은 경우에는 데이터 타입으로 varchar로 정의하나요? 아니면 bigint로 정의하는가
bigin
가 맞습니다.Varchar
로 하면 일반적으로 상품 가격을 올려야 하는 상황에서 애플리케이션에서만 가능, 데이터베이스에서 원자적 연산이 가능하기 위해서는bigint
를 사용해야 한다.- 연산이 필요할 때는
bigint
를 사용하자.
- 데이터베이스에 관한 강의나 교재를 추천해주세요!
- 전반적인 개념을 배울 때는 책으로 공부 추천
- 그 때 그 때 필요한 것들은 책 뿐만 아니라 인터넷에서 블로그들을 많이 찾아보는 것을 추천
- 책은
Real My SQL
추천
부족한 점이나 잘못 된 점을 알려주시면 시정하겠습니다 :>
728x90
'프로젝트 > 카카오 테크 캠퍼스' 카테고리의 다른 글
🐥 카카오테크캠퍼스 - 2단계 2주차 과제 - 예외처리 (0) | 2023.07.04 |
---|---|
🐥 카카오테크캠퍼스 - 2단계 2주차 과제 (0) | 2023.07.03 |
🐥 카카오테크캠퍼스 - 2단계 1주차 Entity 세부 설계 (0) | 2023.06.28 |
🐥 카카오테크캠퍼스 - 2단계 1주차 Entity 기본 설계 (0) | 2023.06.27 |
🐥 카카오테크캠퍼스 - 2단계 1주차 과제 분석 (0) | 2023.06.27 |