Ver3.0 ๐ ์ผํ๋ชฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ ์๋ฒฝ ๊ฐ์ด๋: ์ํยท์ฃผ๋ฌธยทํ์ ๊ด๋ฆฌ ๊ตฌ์กฐ์ ๋ชจ๋ ๊ฒ

๐ ์ผํ๋ชฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ ์๋ฒฝ ๊ฐ์ด๋: ์ํยท์ฃผ๋ฌธยทํ์ ๊ด๋ฆฌ ๊ตฌ์กฐ์ ๋ชจ๋ ๊ฒ
์ค๋ฌด์์ ๋ฐ๋ก ์จ๋จน๋ ์ผํ๋ชฐ DB ์ค๊ณ ๋ ธํ์ฐ ๐ก
๐ฏ ์ผํ๋ชฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ ์ค์ํ ๊น?
์๋
! ์ค๋์ ์ผํ๋ชฐ์ ๋ง๋ค ๋ ๊ฐ์ฅ ํต์ฌ์ด ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ. ๐
์ผํ๋ชฐ์ ์ด์ํ๋ค๋ ๊ฑด ๋จ์ํ ์์ ํ๋ฉด๋ง ๋ง๋๋ ๊ฒ ์๋์ผ. ์๋ง์ ์ํ ์ ๋ณด, ํ์๋ค์ ๊ฐ์ธ์ ๋ณด, ๋งค์ผ๋งค์ผ ์์ด๋ ์ฃผ๋ฌธ ๋ฐ์ดํฐ... ์ด ๋ชจ๋ ๊ฑธ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ์ง ์์ผ๋ฉด ๋์ค์ ์ ๋ง ํฐ์ผ ๋๊ฑฐ๋ ! ๐ฅ
์ค์ ๋ก ๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ฒ์์ "๋์ถฉ ํ
์ด๋ธ ๋ช ๊ฐ ๋ง๋ค๋ฉด ๋๊ฒ ์ง?"๋ผ๊ณ ์๊ฐํ๋ค๊ฐ, ๋์ค์ ๋ฐ์ดํฐ๊ฐ ๊ผฌ์ด๊ณ ์ฑ๋ฅ์ด ๋จ์ด์ ธ์ ์ ์ฒด๋ฅผ ๋ค์ ์ค๊ณํ๋ ๊ฒฝ์ฐ๊ฐ ์ ๋ง ๋ง์. ๋๋ ์์ ์ ๊ทธ๋ฐ ๊ฒฝํ์ด ์์ด์... ๐
๊ทธ๋์ ์ค๋์ ์ค๋ฌด์์ ๋ฐ๋ก ์ ์ฉํ ์ ์๋ ์ผํ๋ชฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ ๋ฐฉ๋ฒ์ ์น๊ตฌํํ
์ค๋ช
ํ๋ฏ์ด ์ฝ๊ฒ ํ์ด๋ณผ๊ฒ!
- โ ์ผํ๋ชฐ DB์ ํต์ฌ 3๋ ์์ (ํ์, ์ํ, ์ฃผ๋ฌธ)
- โ ์ค๋ฌด์์ ์ฌ์ฉํ๋ ํ ์ด๋ธ ๊ตฌ์กฐ์ ๊ด๊ณ ์ค์
- โ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ธ๋ฑ์ค ์ ๋ต
- โ ํ์ฅ ๊ฐ๋ฅํ ์ค๊ณ ํจํด
- โ ์ค์ SQL ์์ ์ฝ๋
๐๏ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ์ ๊ธฐ๋ณธ ์์น
๋ณธ๊ฒฉ์ ์ผ๋ก ์ผํ๋ชฐ DB๋ฅผ ์ค๊ณํ๊ธฐ ์ ์, ๋จผ์ ์์์ผ ํ ๊ธฐ๋ณธ ์์น๋ค์ด ์์ด. ์ด๊ฑธ ๋ชจ๋ฅด๊ณ ์์ํ๋ฉด ๋์ค์ ๊ผญ ํํํ๊ฒ ๋๊ฑฐ๋ ! ๐ฑ
์ ๊ทํ๋ผ๋ ๋ง ๋ค์ด๋ดค์ง? ๊ฐ๋จํ ๋งํ๋ฉด ๋ฐ์ดํฐ ์ค๋ณต์ ์ต์ํํ๊ณ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๋ ๊ฑฐ์ผ.
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. ๋ง์ฝ ์ฃผ๋ฌธ ํ
์ด๋ธ์ ๊ณ ๊ฐ ์ด๋ฆ, ์ ํ๋ฒํธ, ์ฃผ์๋ฅผ ๋ชจ๋ ์ ์ฅํ๋ค๋ฉด?
๊ฐ์ ๊ณ ๊ฐ์ด 10๋ฒ ์ฃผ๋ฌธํ๋ฉด ๋์ผํ ์ ๋ณด๊ฐ 10๋ฒ ์ค๋ณต ์ ์ฅ๋๋ ๊ฑฐ์ง. ๊ทธ๋ฆฌ๊ณ ๊ณ ๊ฐ์ด ์ ํ๋ฒํธ๋ฅผ ๋ฐ๊พธ๋ฉด? 10๊ฐ์ ๋ ์ฝ๋๋ฅผ ๋ชจ๋ ์์ ํด์ผ ํด! ๐ฐ
๊ทธ๋์ ์ฐ๋ฆฌ๋ ํ์ ์ ๋ณด๋ ํ์ ํ
์ด๋ธ์, ์ฃผ๋ฌธ ์ ๋ณด๋ ์ฃผ๋ฌธ ํ
์ด๋ธ์ ๋ถ๋ฆฌํด์ ์ ์ฅํ๊ณ , ๋์ ์ธ๋ํค(Foreign Key)๋ก ์ฐ๊ฒฐํ๋ ๊ฑฐ์ผ.
1์ฐจ ์ ๊ทํ (1NF)
- ๋ชจ๋ ์์ฑ์ ์์๊ฐ(Atomic Value)์ ๊ฐ์ ธ์ผ ํจ
- ๋ฐ๋ณต๋๋ ๊ทธ๋ฃน์ด ์์ด์ผ ํจ
2์ฐจ ์ ๊ทํ (2NF)
- 1NF๋ฅผ ๋ง์กฑํ๋ฉด์
- ๋ถ๋ถ ํจ์ ์ข ์์ฑ์ ์ ๊ฑฐ (๊ธฐ๋ณธํค์ ์ผ๋ถ์๋ง ์ข ์๋๋ ์์ฑ ์ ๊ฑฐ)
3์ฐจ ์ ๊ทํ (3NF)
- 2NF๋ฅผ ๋ง์กฑํ๋ฉด์
- ์ดํ์ ํจ์ ์ข ์์ฑ์ ์ ๊ฑฐ (๊ธฐ๋ณธํค๊ฐ ์๋ ์์ฑ์ ์ข ์๋๋ ์์ฑ ์ ๊ฑฐ)
์ค๋ฌด์์๋ ๋ณดํต 3์ฐจ ์ ๊ทํ๊น์ง๋ง ์ ์ฉํด. ๊ทธ ์ด์์ ์คํ๋ ค ๋ณต์ก๋๋ง ๋์์ง ์ ์๊ฑฐ๋ ! ๐ค
"์ด? ๊ทธ๋ผ ๋ฌด์กฐ๊ฑด ์ ๊ทํ๊ฐ ์ข์ ๊ฑฐ ์๋์ผ?"๋ผ๊ณ ์๊ฐํ ์ ์๋๋ฐ, ๊ผญ ๊ทธ๋ ์ง๋ง์ ์์! ๐
์ ๊ทํ๋ฅผ ๋๋ฌด ๋ง์ด ํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ ์ฌ๋ฌ ํ
์ด๋ธ์ JOINํด์ผ ํด์ ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ์์ด. ํนํ ์กฐํ๊ฐ ๋ง์ ์ผํ๋ชฐ์์๋ ์น๋ช
์ ์ด์ง!
๊ทธ๋์ ์ค๋ฌด์์๋ ์ ์ ํ ์ญ์ ๊ทํ๋ฅผ ํตํด ์ฑ๋ฅ์ ์ต์ ํํด. ์๋ฅผ ๋ค๋ฉด:
โข ์ฃผ๋ฌธ ํ ์ด๋ธ์ ์ํ๋ช ์ ์ค๋ณต ์ ์ฅ (์ํ๋ช ์ด ๋ณ๊ฒฝ๋์ด๋ ๊ณผ๊ฑฐ ์ฃผ๋ฌธ ๋ด์ญ์ ์ ์ง)
โข ํต๊ณ์ฉ ์ง๊ณ ํ ์ด๋ธ ๋ณ๋ ์์ฑ (๋งค๋ฒ ๊ณ์ฐํ์ง ์๊ณ ๋ฏธ๋ฆฌ ๊ณ์ฐ๋ ๊ฐ ์ ์ฅ)
โข ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ๋ ์บ์ ํ ์ด๋ธ๋ก ๋ถ๋ฆฌ
๐ฅ ํ์ ๊ด๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ผํ๋ชฐ์ ํต์ฌ ํ ์ด๋ธ๋ค์ ์ค๊ณํด๋ณด์! ๋จผ์ ํ์ ๊ด๋ฆฌ๋ถํฐ ์์ํ ๊ฒ. ๐
ํ์ ํ ์ด๋ธ์ ์ผํ๋ชฐ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋ ํ ์ด๋ธ์ด์ผ. ์ฌ๊ธฐ์ ์ค์ํ ๊ฑด ํ์ฅ ๊ฐ๋ฅ์ฑ์ ๊ณ ๋ คํ๋ ๊ฑฐ์ผ!
CREATE TABLE members (
member_id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(50) NOT NULL,
phone VARCHAR(20),
birth_date DATE,
gender ENUM('M', 'F', 'O') DEFAULT 'O',
member_grade ENUM('BRONZE', 'SILVER', 'GOLD', 'VIP') DEFAULT 'BRONZE',
total_purchase_amount DECIMAL(15,2) DEFAULT 0,
point_balance INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
email_verified BOOLEAN DEFAULT FALSE,
marketing_agreed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_login_at TIMESTAMP NULL,
INDEX idx_email (email),
INDEX idx_phone (phone),
INDEX idx_member_grade (member_grade),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ๋น๋ฐ๋ฒํธ๋ ์ ๋ ํ๋ฌธ์ผ๋ก ์ ์ฅํ๋ฉด ์ ๋ผ! bcrypt, Argon2 ๊ฐ์ ํด์ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ ํ์
โข ๊ฐ์ธ์ ๋ณด๋ ์ํธํ ์ ์ฅ ๊ณ ๋ ค (ํนํ ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ, ๊ณ์ข๋ฒํธ ๋ฑ)
โข GDPR, ๊ฐ์ธ์ ๋ณด๋ณดํธ๋ฒ ์ค์๋ฅผ ์ํ ๋์ ์ฌ๋ถ ํ๋ ํ์
ํ ํ์์ด ์ฌ๋ฌ ๋ฐฐ์ก์ง๋ฅผ ๊ฐ์ง ์ ์์ผ๋๊น, ์ฃผ์๋ ๋ณ๋ ํ ์ด๋ธ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ ์ข์! ๐ฆ
CREATE TABLE member_addresses (
address_id BIGINT PRIMARY KEY AUTO_INCREMENT,
member_id BIGINT NOT NULL,
address_name VARCHAR(50) NOT NULL COMMENT '๋ฐฐ์ก์ง๋ช
(์: ์ง, ํ์ฌ)',
recipient_name VARCHAR(50) NOT NULL,
recipient_phone VARCHAR(20) NOT NULL,
postal_code VARCHAR(10) NOT NULL,
address_line1 VARCHAR(200) NOT NULL COMMENT '๊ธฐ๋ณธ์ฃผ์',
address_line2 VARCHAR(200) COMMENT '์์ธ์ฃผ์',
is_default BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE,
INDEX idx_member_id (member_id),
INDEX idx_is_default (member_id, is_default)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
์ฌ๊ธฐ์ ON DELETE CASCADE๋ฅผ ์ฌ์ฉํ ์ด์ ๋ ํ์์ด ํํดํ๋ฉด ๊ด๋ จ ์ฃผ์๋ ์๋์ผ๋ก ์ญ์ ๋๋๋ก ํ๊ธฐ ์ํด์์ผ. ํ์ง๋ง ์ค๋ฌด์์๋ ํ์ ํํด ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ก ์ญ์ ํ์ง ์๊ณ ์ํํธ ์ญ์ (Soft Delete) ๋ฐฉ์์ ๋ง์ด ์ฌ์ฉํด!
์ผํ๋ชฐ์์ ํ์ ๋ฑ๊ธ์ ์ ๋ง ์ค์ํด! ๋ฑ๊ธ์ ๋ฐ๋ผ ํ ์ธ์จ, ์ ๋ฆฝ๋ฅ , ํํ์ด ๋ฌ๋ผ์ง๋๊น. ๐
๊ฐ๋จํ ์ผํ๋ชฐ์ด๋ผ๋ฉด members ํ
์ด๋ธ์ member_grade ์ปฌ๋ผ์ผ๋ก ์ถฉ๋ถํ์ง๋ง, ๋ณต์กํ ๋ฑ๊ธ ์์คํ
์ด ํ์ํ๋ค๋ฉด ๋ณ๋ ํ
์ด๋ธ๋ก ๊ด๋ฆฌํ๋ ๊ฒ ์ข์:
CREATE TABLE member_grades (
grade_id INT PRIMARY KEY AUTO_INCREMENT,
grade_name VARCHAR(20) NOT NULL,
min_purchase_amount DECIMAL(15,2) NOT NULL COMMENT '๋ฑ๊ธ ๋ฌ์ฑ ์ต์ ๊ตฌ๋งค์ก',
discount_rate DECIMAL(5,2) DEFAULT 0 COMMENT 'ํ ์ธ์จ (%)',
point_rate DECIMAL(5,2) DEFAULT 1 COMMENT '์ ๋ฆฝ๋ฅ (%)',
free_shipping_threshold DECIMAL(10,2) COMMENT '๋ฌด๋ฃ๋ฐฐ์ก ๊ธฐ์ค๊ธ์ก',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ๊ธฐ๋ณธ ๋ฑ๊ธ ๋ฐ์ดํฐ ์ฝ์
INSERT INTO member_grades (grade_name, min_purchase_amount, discount_rate, point_rate) VALUES
('BRONZE', 0, 0, 1),
('SILVER', 100000, 3, 1.5),
('GOLD', 500000, 5, 2),
('VIP', 1000000, 10, 3);
๐๏ธ ์ํ ๊ด๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ
์ด์ ์ผํ๋ชฐ์ ๊ฝ! ์ํ ๊ด๋ฆฌ ๋ถ๋ถ์ ์ค๊ณํด๋ณผ๊ฒ. ์ํ DB๋ ์๊ฐ๋ณด๋ค ๋ณต์กํด์ ์ ์คํ๊ฒ ์ค๊ณํด์ผ ํด! ๐จ
์ํ์ ๋ถ๋ฅํ๊ธฐ ์ํ ์นดํ ๊ณ ๋ฆฌ๋ถํฐ ๋ง๋ค์ด๋ณด์. ์นดํ ๊ณ ๋ฆฌ๋ ๋ณดํต ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง์ง? (์: ์๋ฅ > ๋จ์ฑ์๋ฅ > ์ ์ธ )
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
parent_category_id INT NULL COMMENT '์์ ์นดํ
๊ณ ๋ฆฌ ID',
category_name VARCHAR(50) NOT NULL,
category_level TINYINT NOT NULL COMMENT '์นดํ
๊ณ ๋ฆฌ ๊น์ด (1: ๋๋ถ๋ฅ, 2: ์ค๋ถ๋ฅ, 3: ์๋ถ๋ฅ)',
display_order INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (parent_category_id) REFERENCES categories(category_id),
INDEX idx_parent (parent_category_id),
INDEX idx_level (category_level),
INDEX idx_display_order (display_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ๊น์ด๋ 3~4๋จ๊ณ๋ฅผ ๋์ง ์๋ ๊ฒ ์ข์ (์ฌ์ฉ์ ๊ฒฝํ ๊ณ ๋ ค)
โข display_order๋ก ๊ด๋ฆฌ์๊ฐ ์ํ๋ ์์๋๋ก ์ ๋ ฌ ๊ฐ๋ฅ
โข ์นดํ ๊ณ ๋ฆฌ ์ญ์ ์ ํ์ ์นดํ ๊ณ ๋ฆฌ์ ์ํ ์ฒ๋ฆฌ ์ ์ฑ ๋ฏธ๋ฆฌ ์ ์ ํ์
๋๋์ด ๋ฉ์ธ ์ด๋ฒคํธ! ์ํ ํ ์ด๋ธ์ด์ผ. ์ฌ๊ธฐ๊ฐ ์ ์ผ ์ค์ํ๋๊น ์ง์ค! ๐ฏ
CREATE TABLE products (
product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
category_id INT NOT NULL,
product_code VARCHAR(50) UNIQUE NOT NULL COMMENT '์ํ ๊ณ ์ ์ฝ๋',
product_name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10,2) NOT NULL,
discount_price DECIMAL(10,2) COMMENT 'ํ ์ธ๊ฐ',
cost_price DECIMAL(10,2) COMMENT '์๊ฐ (๊ด๋ฆฌ์ฉ)',
stock_quantity INT DEFAULT 0,
min_order_quantity INT DEFAULT 1,
max_order_quantity INT DEFAULT 999,
weight DECIMAL(8,2) COMMENT '๋ฌด๊ฒ(kg)',
manufacturer VARCHAR(100) COMMENT '์ ์กฐ์ฌ',
brand VARCHAR(100) COMMENT '๋ธ๋๋',
origin_country VARCHAR(50) COMMENT '์์ฐ์ง',
is_display BOOLEAN DEFAULT TRUE,
is_soldout BOOLEAN DEFAULT FALSE,
view_count INT DEFAULT 0,
sales_count INT DEFAULT 0,
rating_average DECIMAL(3,2) DEFAULT 0,
review_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(category_id),
INDEX idx_category (category_id),
INDEX idx_product_code (product_code),
INDEX idx_price (price),
INDEX idx_created_at (created_at),
INDEX idx_sales_count (sales_count),
INDEX idx_rating (rating_average),
FULLTEXT INDEX ft_idx_name_desc (product_name, description)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
์ฌ๊ธฐ์ ์ฃผ๋ชฉํ ์ ! ๐
1. FULLTEXT INDEX
์ํ๋ช
๊ณผ ์ค๋ช
์ผ๋ก ๊ฒ์ํ ๋ ์ฑ๋ฅ์ ๋์ด๊ธฐ ์ํด ์ ๋ฌธ ๊ฒ์ ์ธ๋ฑ์ค๋ฅผ ์ถ๊ฐํ์ด. ํ์ง๋ง ํ๊ธ ๊ฒ์์ MySQL 5.7.6 ์ด์์์๋ง ์ ๋๋ก ์๋ํ๋ ์ฃผ์!
2. ์ฌ๊ณ ๊ด๋ฆฌ
stock_quantity๋ ์ค์๊ฐ์ผ๋ก ๋ณํ๋ ๊ฐ์ด๋ผ ๋์์ฑ ์ ์ด๊ฐ ์ค์ํด. ๋์ค์ ์ฃผ๋ฌธ ์ฒ๋ฆฌํ ๋ ์์ธํ ๋ค๋ฃฐ๊ฒ!
3. ํต๊ณ ์ ๋ณด
view_count, sales_count, rating_average ๊ฐ์ ์ง๊ณ ๋ฐ์ดํฐ๋ ์ญ์ ๊ทํ์ ์ข์ ์์์ผ. ๋งค๋ฒ ๊ณ์ฐํ๋ฉด ๋๋ฆฌ๋๊น ๋ฏธ๋ฆฌ ์ ์ฅํด๋๋ ๊ฑฐ์ง! ๐
์ท์ด๋ผ๋ฉด ์ฌ์ด์ฆ์ ์์, ์ ์์ ํ์ด๋ผ๋ฉด ์ฉ๋๊ณผ ์์... ์ด๋ฐ ์ต์
๋ค์ ์ด๋ป๊ฒ ๊ด๋ฆฌํ ๊น? ๐ค
์ต์
๊ด๋ฆฌ๋ ์ ๋ง ๊น๋ค๋ก์ด ๋ถ๋ถ์ด์ผ. ์ฌ๋ฌ ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๊ฐ์ฅ ์ ์ฐํ ๋ฐฉ์์ ์๊ฐํ ๊ฒ:
-- ์ต์
๊ทธ๋ฃน ํ
์ด๋ธ (์: ์์, ์ฌ์ด์ฆ)
CREATE TABLE product_option_groups (
option_group_id INT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
group_name VARCHAR(50) NOT NULL COMMENT '์ต์
๋ช
(์: ์์, ์ฌ์ด์ฆ)',
display_order INT DEFAULT 0,
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
INDEX idx_product (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ์ต์
๊ฐ ํ
์ด๋ธ (์: ๋นจ๊ฐ, ํ๋ / S, M, L)
CREATE TABLE product_option_values (
option_value_id INT PRIMARY KEY AUTO_INCREMENT,
option_group_id INT NOT NULL,
value_name VARCHAR(50) NOT NULL,
additional_price DECIMAL(10,2) DEFAULT 0 COMMENT '์ถ๊ฐ ๊ธ์ก',
display_order INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
FOREIGN KEY (option_group_id) REFERENCES product_option_groups(option_group_id) ON DELETE CASCADE,
INDEX idx_option_group (option_group_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ์ต์
์กฐํฉ๋ณ ์ฌ๊ณ ๊ด๋ฆฌ (์: ๋นจ๊ฐ-S, ๋นจ๊ฐ-M, ํ๋-S...)
CREATE TABLE product_option_stocks (
stock_id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
option_combination VARCHAR(200) NOT NULL COMMENT '์ต์
์กฐํฉ (JSON ๋๋ ๊ตฌ๋ถ์)',
sku VARCHAR(100) UNIQUE COMMENT 'Stock Keeping Unit',
stock_quantity INT DEFAULT 0,
additional_price DECIMAL(10,2) DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
INDEX idx_product (product_id),
INDEX idx_sku (sku)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ํฐ์ ์ธ ๋ฅผ ํ๋งคํ๋ค๊ณ ๊ฐ์ ํด๋ณด์:
product_option_groups
- ๊ทธ๋ฃน1: ์์
- ๊ทธ๋ฃน2: ์ฌ์ด์ฆ
product_option_values
- ์์: ๋นจ๊ฐ, ํ๋, ๊ฒ์
- ์ฌ์ด์ฆ: S, M, L, XL
product_option_stocks
- ๋นจ๊ฐ-S: ์ฌ๊ณ 10๊ฐ
- ๋นจ๊ฐ-M: ์ฌ๊ณ 15๊ฐ
- ํ๋-S: ์ฌ๊ณ 5๊ฐ
- ... (์ด 12๊ฐ ์กฐํฉ)
์ผํ๋ชฐ์์ ์ด๋ฏธ์ง๋ ์ ๋ง ์ค์ํ์ง! ํ ์ํ์ ์ฌ๋ฌ ์ด๋ฏธ์ง๊ฐ ํ์ํ๋๊น ๋ณ๋ ํ ์ด๋ธ๋ก ๊ด๋ฆฌํด์ผ ํด. ๐ธ
CREATE TABLE product_images (
image_id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
image_url VARCHAR(500) NOT NULL,
thumbnail_url VARCHAR(500),
image_type ENUM('MAIN', 'SUB', 'DETAIL') DEFAULT 'SUB',
display_order INT DEFAULT 0,
alt_text VARCHAR(200) COMMENT 'SEO์ฉ ๋์ฒด ํ
์คํธ',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
INDEX idx_product (product_id),
INDEX idx_type (product_id, image_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ์๋ณธ ์ด๋ฏธ์ง๋ CDN์ ์ ์ฅํ๊ณ URL๋ง DB์ ์ ์ฅ
โข ์ธ๋ค์ผ์ ์๋ ์์ฑํ์ฌ ๋ณ๋ ์ ์ฅ (๋ก๋ฉ ์๋ ๊ฐ์ )
โข ์ด๋ฏธ์ง ํ์ผ๋ช ์ UUID ๋ฑ์ผ๋ก ์ค๋ณต ๋ฐฉ์ง
โข WebP ํฌ๋งท ์ฌ์ฉ ๊ณ ๋ ค (์ฉ๋ 30% ๊ฐ์)
๐ฆ ์ฃผ๋ฌธ ๊ด๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ
์, ์ด์ ๊ฐ์ฅ ๋ณต์กํ์ง๋ง ๊ฐ์ฅ ์ค์ํ ์ฃผ๋ฌธ ๊ด๋ฆฌ ๋ถ๋ถ์ด์ผ! ์ฌ๊ธฐ์ ์ค์ํ๋ฉด ๋์ด ์๋ค๊ฐ๋คํ๋ ๊ฑฐ๋ผ ์ ๋ง ์กฐ์ฌํด์ผ ํด! ๐ฐ
์ฃผ๋ฌธ ํ ์ด๋ธ์ ์ฃผ๋ฌธ์ ํค๋ ์ ๋ณด๋ฅผ ๋ด๋ ๊ฑฐ์ผ. ๋๊ฐ, ์ธ์ , ์ผ๋ง์ ์ฃผ๋ฌธํ๋์ง ๊ฐ์ ๊ธฐ๋ณธ ์ ๋ณด๋ค!
CREATE TABLE orders (
order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_number VARCHAR(50) UNIQUE NOT NULL COMMENT '์ฃผ๋ฌธ๋ฒํธ (๊ณ ๊ฐ์๊ฒ ๋ณด์ฌ์ง๋)',
member_id BIGINT NOT NULL,
order_status ENUM('PENDING', 'PAID', 'PREPARING', 'SHIPPING', 'DELIVERED', 'CANCELLED', 'REFUNDED') DEFAULT 'PENDING',
payment_method ENUM('CARD', 'BANK_TRANSFER', 'VIRTUAL_ACCOUNT', 'MOBILE', 'POINT') NOT NULL,
payment_status ENUM('PENDING', 'COMPLETED', 'FAILED', 'CANCELLED') DEFAULT 'PENDING',
-- ๊ธ์ก ์ ๋ณด
total_product_price DECIMAL(12,2) NOT NULL COMMENT '์ํ ์ด์ก',
total_discount_amount DECIMAL(12,2) DEFAULT 0 COMMENT 'ํ ์ธ ์ด์ก',
delivery_fee DECIMAL(8,2) DEFAULT 0 COMMENT '๋ฐฐ์ก๋น',
total_payment_amount DECIMAL(12,2) NOT NULL COMMENT '์ต์ข
๊ฒฐ์ ๊ธ์ก',
used_point INT DEFAULT 0 COMMENT '์ฌ์ฉ ํฌ์ธํธ',
earned_point INT DEFAULT 0 COMMENT '์ ๋ฆฝ ํฌ์ธํธ',
-- ๋ฐฐ์ก ์ ๋ณด
recipient_name VARCHAR(50) NOT NULL,
recipient_phone VARCHAR(20) NOT NULL,
postal_code VARCHAR(10) NOT NULL,
address_line1 VARCHAR(200) NOT NULL,
address_line2 VARCHAR(200),
delivery_message TEXT COMMENT '๋ฐฐ์ก ๋ฉ์์ง',
-- ๊ธฐํ
order_memo TEXT COMMENT '์ฃผ๋ฌธ ๋ฉ๋ชจ',
admin_memo TEXT COMMENT '๊ด๋ฆฌ์ ๋ฉ๋ชจ',
cancelled_at TIMESTAMP NULL,
cancel_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id),
INDEX idx_member (member_id),
INDEX idx_order_number (order_number),
INDEX idx_status (order_status),
INDEX idx_created_at (created_at),
INDEX idx_payment_status (payment_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
order_id๋ ๋ด๋ถ์ฉ ์๋์ฆ๊ฐ ๊ฐ์ด๊ณ , order_number๋ ๊ณ ๊ฐ์๊ฒ ๋ณด์ฌ์ง๋ ์ฃผ๋ฌธ๋ฒํธ์ผ!
์ฃผ๋ฌธ๋ฒํธ ์์ฑ ์์: ORD20240115001234 (์ฃผ๋ฌธ์ผ์ + ์ํ์ค)
โข ์ถ์ธก ๊ฐ๋ฅํ ํจํด์ ํผํ ๊ฒ (๋ณด์)
โข ์ค๋ณต ๋ฐฉ์ง๋ฅผ ์ํ UNIQUE ์ ์ฝ ํ์
โข ๊ณ ๊ฐ ๋ฌธ์ ์ ์ฝ๊ฒ ์ฐพ์ ์ ์๋๋ก ๊ฐ๊ฒฐํ๊ฒ
ํ ์ฃผ๋ฌธ์๋ ์ฌ๋ฌ ์ํ์ด ๋ค์ด๊ฐ ์ ์์ง? ๊ทธ๋์ ์ฃผ๋ฌธ ์์ธ ํ ์ด๋ธ์ด ํ์ํด! ๐
CREATE TABLE order_items (
order_item_id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
product_name VARCHAR(200) NOT NULL COMMENT '์ฃผ๋ฌธ ๋น์ ์ํ๋ช
(๋ณ๊ฒฝ ๋๋น)',
product_code VARCHAR(50) NOT NULL,
option_info VARCHAR(500) COMMENT '์ ํํ ์ต์
์ ๋ณด (JSON)',
sku VARCHAR(100) COMMENT 'SKU',
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL COMMENT '๋จ๊ฐ',
discount_amount DECIMAL(10,2) DEFAULT 0 COMMENT '์ํ๋ณ ํ ์ธ์ก',
total_price DECIMAL(12,2) NOT NULL COMMENT '์๊ณ (๋จ๊ฐ * ์๋ - ํ ์ธ)',
item_status ENUM('PENDING', 'CONFIRMED', 'PREPARING', 'SHIPPING', 'DELIVERED', 'CANCELLED', 'REFUNDED') DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(product_id),
INDEX idx_order (order_id),
INDEX idx_product (product_id),
INDEX idx_status (item_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
์ฌ๊ธฐ์ ์ค์ํ ํฌ์ธํธ! ๐ฏ
์ product_name์ ์ค๋ณต ์ ์ฅํ ๊น?
์ํ๋ช
์ด ๋์ค์ ๋ณ๊ฒฝ๋์ด๋ ์ฃผ๋ฌธ ๋ด์ญ์ ์ฃผ๋ฌธ ๋น์์ ์ ๋ณด๋ฅผ ์ ์งํด์ผ ํ๊ธฐ ๋๋ฌธ์ด์ผ! ์ด๊ฒ ๋ฐ๋ก ์ญ์ ๊ทํ์ ์ค์ฉ์ ์ธ ์์์ง. ๐
์ต์
์ ๋ณด๋ ์ด๋ป๊ฒ ์ ์ฅํ ๊น?
option_info ์ปฌ๋ผ์ JSON ํํ๋ก ์ ์ฅํ๋ ๊ฒ ํธํด. ์๋ฅผ ๋ค๋ฉด:
{"์์": "๋นจ๊ฐ", "์ฌ์ด์ฆ": "M"}
์ฃผ๋ฌธ ์ ์ ์ฅ๋ฐ๊ตฌ๋๊ฐ ์์ด์ผ๊ฒ ์ง? ์ฅ๋ฐ๊ตฌ๋๋ ์์ ๋ฐ์ดํฐ๋ผ์ ์ค๊ณ๊ฐ ์ข ๋ฌ๋ผ! ๐
CREATE TABLE cart_items (
cart_id BIGINT PRIMARY KEY AUTO_INCREMENT,
member_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
option_info VARCHAR(500) COMMENT '์ ํํ ์ต์
(JSON)',
sku VARCHAR(100),
quantity INT NOT NULL DEFAULT 1,
is_selected BOOLEAN DEFAULT TRUE COMMENT '์ฃผ๋ฌธ ์ ์ ํ ์ฌ๋ถ',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
INDEX idx_member (member_id),
INDEX idx_product (product_id),
UNIQUE KEY unique_cart_item (member_id, product_id, sku)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ๋นํ์ ์ฅ๋ฐ๊ตฌ๋๋ ์ธ์ ์ด๋ ์ฟ ํค๋ก ๊ด๋ฆฌ (๋ก๊ทธ์ธ ์ DB๋ก ์ด์ )
โข ์ค๋๋ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ ์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ญ์ (์: 30์ผ ์ด์)
โข ์ฌ๊ณ ๋ถ์กฑ ์ ์ฅ๋ฐ๊ตฌ๋์์ ์๋ ์ ๊ฑฐ ๋๋ ์๋ฆผ
โข ๊ฐ๊ฒฉ ๋ณ๋ ์ ์ฅ๋ฐ๊ตฌ๋์์ ์ต์ ๊ฐ๊ฒฉ์ผ๋ก ํ์
๊ฒฐ์ ์ ๋ณด๋ ์ ๋ง ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ผ์ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ ๊ฒ ์ข์! ๐ณ
CREATE TABLE payments (
payment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
payment_method ENUM('CARD', 'BANK_TRANSFER', 'VIRTUAL_ACCOUNT', 'MOBILE', 'POINT') NOT NULL,
payment_amount DECIMAL(12,2) NOT NULL,
payment_status ENUM('PENDING', 'COMPLETED', 'FAILED', 'CANCELLED', 'REFUNDED') DEFAULT 'PENDING',
-- PG์ฌ ์ ๋ณด
pg_provider VARCHAR(50) COMMENT 'PG์ฌ๋ช
(์: ํ ์คํ์ด๋จผ์ธ , ๋์ด์คํ์ด)',
pg_transaction_id VARCHAR(100) COMMENT 'PG์ฌ ๊ฑฐ๋ ID',
approval_number VARCHAR(50) COMMENT '์น์ธ๋ฒํธ',
-- ์นด๋ ์ ๋ณด (๋ง์คํน ์ฒ๋ฆฌ)
card_company VARCHAR(50),
card_number_masked VARCHAR(20) COMMENT '๋ง์คํน๋ ์นด๋๋ฒํธ (์: 1234-****-****-5678)',
installment_month TINYINT DEFAULT 0 COMMENT 'ํ ๋ถ ๊ฐ์ (0: ์ผ์๋ถ)',
-- ๊ฐ์๊ณ์ข ์ ๋ณด
virtual_account_bank VARCHAR(50),
virtual_account_number VARCHAR(50),
virtual_account_holder VARCHAR(50),
virtual_account_due_date TIMESTAMP NULL,
paid_at TIMESTAMP NULL,
cancelled_at TIMESTAMP NULL,
cancel_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES orders(order_id),
INDEX idx_order (order_id),
INDEX idx_pg_transaction (pg_transaction_id),
INDEX idx_status (payment_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ์นด๋๋ฒํธ ์ ์ฒด๋ ์ ๋ ์ ์ฅ ๊ธ์ง! (PCI-DSS ์๋ฐ)
โข ๋ง์คํน๋ ์ ๋ณด๋ง ์ ์ฅ (์: 1234-****-****-5678)
โข ์ค์ ๊ฒฐ์ ๋ PG์ฌ API๋ฅผ ํตํด ์ฒ๋ฆฌ
โข ๊ฒฐ์ ๋ก๊ทธ๋ ๋ณ๋ ์ํธํ ์ ์ฅ ๊ณ ๋ ค
โข ๊ฐ์ธ์ ๋ณด ๋ณด์ ๊ธฐ๊ฐ ์ค์ (์ ์์๊ฑฐ๋๋ฒ: 5๋ )
โก ์ฑ๋ฅ ์ต์ ํ ์ ๋ต
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ๊ฐ ๋๋ฌ๋ค๊ณ ๋์ด ์๋์ผ! ์ค์ ์๋น์ค์์๋ ์ฑ๋ฅ์ด ์ ๋ง ์ค์ํ๊ฑฐ๋ . ๐
ํนํ ์ผํ๋ชฐ์ ๋์ ์ ์์๊ฐ ๋ง๊ณ , ์ฃผ๋ฌธ์ด ๋ชฐ๋ฆฌ๋ ์๊ฐ๋๊ฐ ์์ด์ ์ฑ๋ฅ ์ต์ ํ๊ฐ ํ์์ผ!
์ธ๋ฑ์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑ๋ฅ์ ์ข์ฐํ๋ ํต์ฌ ์์์ผ. ํ์ง๋ง ๋ฌด์์ ๋ง์ด ๋ง๋ค๋ฉด ์คํ๋ ค ๋ ์ด ๋ ์ ์์ด! ๐ฏ
โ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ๊ฒฝ์ฐ
โข WHERE ์ ์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
โข JOIN ์กฐ๊ฑด์ผ๋ก ์ฌ์ฉ๋๋ ์ปฌ๋ผ
โข ORDER BY, GROUP BY์ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
โข ์นด๋๋๋ฆฌํฐ(๊ณ ์ ๊ฐ์ ๋น์จ)๊ฐ ๋์ ์ปฌ๋ผ
โ ์ธ๋ฑ์ค๋ฅผ ํผํด์ผ ํ๋ ๊ฒฝ์ฐ
โข ๋ฐ์ดํฐ ๋ณ๊ฒฝ(INSERT, UPDATE, DELETE)์ด ๋น๋ฒํ ์ปฌ๋ผ
โข ํ ์ด๋ธ ํฌ๊ธฐ๊ฐ ์์ ๊ฒฝ์ฐ (์์ฒ ๊ฑด ์ดํ)
โข ์นด๋๋๋ฆฌํฐ๊ฐ ๋ฎ์ ์ปฌ๋ผ (์: ์ฑ๋ณ, Boolean)
โข ์ปฌ๋ผ ๊ฐ์ ๋๋ถ๋ถ์ด NULL์ธ ๊ฒฝ์ฐ
-- ๋ณตํฉ ์ธ๋ฑ์ค ์์ (์ฃผ๋ฌธ ์กฐํ ์ต์ ํ)
CREATE INDEX idx_order_search
ON orders(member_id, order_status, created_at);
-- ์ด๋ ๊ฒ ํ๋ฉด ์๋ ์ฟผ๋ฆฌ๋ค์ด ๋ชจ๋ ์ธ๋ฑ์ค๋ฅผ ํ์ฉํ ์ ์์ด!
-- SELECT * FROM orders WHERE member_id = 123;
-- SELECT * FROM orders WHERE member_id = 123 AND order_status = 'PAID';
-- SELECT * FROM orders WHERE member_id = 123 AND order_status = 'PAID'
-- ORDER BY created_at DESC;
-- ์ปค๋ฒ๋ง ์ธ๋ฑ์ค (์ฟผ๋ฆฌ์ ํ์ํ ๋ชจ๋ ์ปฌ๋ผ์ ์ธ๋ฑ์ค์ ํฌํจ)
CREATE INDEX idx_product_list
ON products(category_id, is_display, created_at, product_id, product_name, price);
-- ์ด๋ ๊ฒ ํ๋ฉด ํ
์ด๋ธ ์ ๊ทผ ์์ด ์ธ๋ฑ์ค๋ง์ผ๋ก ๊ฒฐ๊ณผ ๋ฐํ ๊ฐ๋ฅ!
-- SELECT product_id, product_name, price
-- FROM products
-- WHERE category_id = 10 AND is_display = TRUE
-- ORDER BY created_at DESC;
์ข์ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์์ด๋ ์ฟผ๋ฆฌ๋ฅผ ์๋ชป ์์ฑํ๋ฉด ์์ฉ์์ด! ์ค๋ฌด์์ ์์ฃผ ์ฐ๋ ์ต์ ํ ๊ธฐ๋ฒ๋ค์ ์๋ ค์ค๊ฒ. ๐ช
-- โ ๋์ ์: SELECT *๋ ํผํ์
SELECT * FROM products WHERE category_id = 10;
-- โ
์ข์ ์: ํ์ํ ์ปฌ๋ผ๋ง ์ ํ
SELECT product_id, product_name, price, thumbnail_url
FROM products
WHERE category_id = 10;
-- โ ๋์ ์: ํจ์ ์ฌ์ฉ์ผ๋ก ์ธ๋ฑ์ค ๋ฌดํจํ
SELECT * FROM orders
WHERE DATE(created_at) = '2024-01-15';
-- โ
์ข์ ์: ๋ฒ์ ์กฐ๊ฑด์ผ๋ก ๋ณ๊ฒฝ
SELECT * FROM orders
WHERE created_at >= '2024-01-15 00:00:00'
AND created_at < '2024-01-16 00:00:00';
-- โ ๋์ ์: OR ์กฐ๊ฑด์ ์ธ๋ฑ์ค ํ์ฉ์ด ์ด๋ ค์
SELECT * FROM products
WHERE category_id = 10 OR category_id = 20;
-- โ
์ข์ ์: IN ์ฌ์ฉ
SELECT * FROM products
WHERE category_id IN (10, 20);
-- โ ๋์ ์: LIKE์ ์์ชฝ ์์ผ๋์นด๋
SELECT * FROM products
WHERE product_name LIKE '%์
์ธ %';
-- โ
์ข์ ์: ์ ๋ฌธ ๊ฒ์ ์ธ๋ฑ์ค ํ์ฉ
SELECT * FROM products
WHERE MATCH(product_name, description) AGAINST('์
์ธ ' IN NATURAL LANGUAGE MODE);
์ผํ๋ชฐ์์ ๊ฐ์ฅ ๊น๋ค๋ก์ด ๋ถ๋ถ์ด ๋ฐ๋ก ์ฌ๊ณ ๊ด๋ฆฌ์ผ! ๐ฐ
์๋ฅผ ๋ค์ด, ์ฌ๊ณ ๊ฐ 1๊ฐ ๋จ์ ์ํ์ 100๋ช
์ด ๋์์ ์ฃผ๋ฌธํ๋ ค๊ณ ํ๋ฉด? ์ ๋๋ก ์ฒ๋ฆฌํ์ง ์์ผ๋ฉด ์ฌ๊ณ ๊ฐ ๋ง์ด๋์ค๊ฐ ๋ ์๋ ์์ด!
-- โ ๋์ ์: Race Condition ๋ฐ์ ๊ฐ๋ฅ
-- 1. ์ฌ๊ณ ํ์ธ
SELECT stock_quantity FROM products WHERE product_id = 123;
-- 2. ์ฌ๊ณ ๊ฐ ์ถฉ๋ถํ๋ฉด ์ฐจ๊ฐ
UPDATE products SET stock_quantity = stock_quantity - 1
WHERE product_id = 123;
-- โ
์ข์ ์ 1: ์์์ ์
๋ฐ์ดํธ (Atomic Update)
UPDATE products
SET stock_quantity = stock_quantity - 1
WHERE product_id = 123
AND stock_quantity >= 1;
-- ์ํฅ๋ฐ์ ํ์ด 0์ด๋ฉด ์ฌ๊ณ ๋ถ์กฑ
-- ์ํฅ๋ฐ์ ํ์ด 1์ด๋ฉด ์ฑ๊ณต
-- โ
์ข์ ์ 2: ๋น๊ด์ ์ ๊ธ (Pessimistic Lock)
START TRANSACTION;
SELECT stock_quantity
FROM products
WHERE product_id = 123
FOR UPDATE; -- ํ ์ ๊ธ
-- ์ฌ๊ณ ํ์ธ ํ ์ฐจ๊ฐ
UPDATE products
SET stock_quantity = stock_quantity - 1
WHERE product_id = 123;
COMMIT;
-- โ
์ข์ ์ 3: ๋๊ด์ ์ ๊ธ (Optimistic Lock)
-- products ํ
์ด๋ธ์ version ์ปฌ๋ผ ์ถ๊ฐ
ALTER TABLE products ADD COLUMN version INT DEFAULT 0;
-- ์
๋ฐ์ดํธ ์ version๋ ํจ๊ป ์ฒดํฌ
UPDATE products
SET stock_quantity = stock_quantity - 1,
version = version + 1
WHERE product_id = 123
AND version = 5 -- ์ฝ์์ ๋์ version
AND stock_quantity >= 1;
-- ์ํฅ๋ฐ์ ํ์ด 0์ด๋ฉด ๋ค๋ฅธ ํธ๋์ญ์
์ด ๋จผ์ ์์ ํจ (์ฌ์๋ ํ์)
1. ์์ ์ฌ๊ณ ์ค์
์ค์ ์ฌ๊ณ ๋ณด๋ค ์ ๊ฒ ํ์ (์: ์ค์ฌ๊ณ 100๊ฐ โ ํ๋งค๊ฐ๋ฅ 95๊ฐ)
2. ์ฌ๊ณ ์์ฝ ์์คํ
์ฃผ๋ฌธ ์ ์ฆ์ ์ฐจ๊ฐํ์ง ์๊ณ '์์ฝ' ์ํ๋ก ๊ด๋ฆฌ
๊ฒฐ์ ์๋ฃ ์ ํ์ , ๊ฒฐ์ ์คํจ ์ ์์ฝ ํด์
3. ์ฌ๊ณ ๋ก๊ทธ ๊ด๋ฆฌ
๋ชจ๋ ์ฌ๊ณ ๋ณ๋ ์ด๋ ฅ์ ๋ณ๋ ํ ์ด๋ธ์ ๊ธฐ๋ก
๋ฌธ์ ๋ฐ์ ์ ์ถ์ ๊ฐ๋ฅ
4. Redis ํ์ฉ
์ค์๊ฐ ์ฌ๊ณ ๋ Redis์์ ๊ด๋ฆฌํ๊ณ ์ฃผ๊ธฐ์ ์ผ๋ก DB ๋๊ธฐํ
-- ์ฌ๊ณ ์ด๋ ฅ ํ
์ด๋ธ
CREATE TABLE stock_histories (
history_id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
sku VARCHAR(100),
change_type ENUM('IN', 'OUT', 'ADJUST', 'RESERVE', 'RELEASE') NOT NULL,
change_quantity INT NOT NULL COMMENT '๋ณ๋๋ (์์: ์ฆ๊ฐ, ์์: ๊ฐ์)',
before_quantity INT NOT NULL,
after_quantity INT NOT NULL,
reference_type VARCHAR(50) COMMENT '์ฐธ์กฐ ํ์
(ORDER, RETURN, MANUAL)',
reference_id BIGINT COMMENT '์ฐธ์กฐ ID',
memo TEXT,
created_by BIGINT COMMENT '์ฒ๋ฆฌ์ ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id),
INDEX idx_product (product_id),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
๐ ๋ถ๊ฐ ๊ธฐ๋ฅ ํ ์ด๋ธ ์ค๊ณ
๊ธฐ๋ณธ์ ์ธ ์ผํ๋ชฐ ๊ธฐ๋ฅ ์ธ์๋ ์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ๋ค์ด ์์ด. ํ๋์ฉ ์ดํด๋ณด์! ๐
์ฟ ํฐ์ ๋ง์ผํ ์ ํต์ฌ ๋๊ตฌ์ผ! ํ ์ธ ์ฟ ํฐ, ๋ฌด๋ฃ๋ฐฐ์ก ์ฟ ํฐ ๋ฑ ๋ค์ํ ํํ๊ฐ ์์ง. ๐ซ
-- ์ฟ ํฐ ๋ง์คํฐ ํ
์ด๋ธ
CREATE TABLE coupons (
coupon_id BIGINT PRIMARY KEY AUTO_INCREMENT,
coupon_code VARCHAR(50) UNIQUE NOT NULL,
coupon_name VARCHAR(100) NOT NULL,
coupon_type ENUM('FIXED', 'PERCENT', 'FREE_SHIPPING') NOT NULL,
discount_value DECIMAL(10,2) NOT NULL COMMENT 'ํ ์ธ๊ฐ (๊ธ์ก ๋๋ %)',
min_purchase_amount DECIMAL(10,2) DEFAULT 0 COMMENT '์ต์ ๊ตฌ๋งค ๊ธ์ก',
max_discount_amount DECIMAL(10,2) COMMENT '์ต๋ ํ ์ธ ๊ธ์ก (% ์ฟ ํฐ์ฉ)',
total_quantity INT COMMENT '์ด ๋ฐํ ์๋ (NULL: ๋ฌด์ ํ)',
used_quantity INT DEFAULT 0,
valid_from TIMESTAMP NOT NULL,
valid_until TIMESTAMP NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_code (coupon_code),
INDEX idx_valid_period (valid_from, valid_until)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ํ์๋ณ ์ฟ ํฐ ๋ฐ๊ธ ํ
์ด๋ธ
CREATE TABLE member_coupons (
member_coupon_id BIGINT PRIMARY KEY AUTO_INCREMENT,
member_id BIGINT NOT NULL,
coupon_id BIGINT NOT NULL,
is_used BOOLEAN DEFAULT FALSE,
used_at TIMESTAMP NULL,
order_id BIGINT COMMENT '์ฌ์ฉํ ์ฃผ๋ฌธ ID',
issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE,
FOREIGN KEY (coupon_id) REFERENCES coupons(coupon_id),
FOREIGN KEY (order_id) REFERENCES orders(order_id),
INDEX idx_member (member_id),
INDEX idx_coupon (coupon_id),
INDEX idx_used (is_used)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
๋ฆฌ๋ทฐ๋ ๊ตฌ๋งค ์ ํ์จ์ ๋์ด๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ผ! ์ ์ค๊ณํด๋ณด์. โญ
CREATE TABLE product_reviews (
review_id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
order_item_id BIGINT NOT NULL COMMENT '๊ตฌ๋งค ํ์ธ์ฉ',
rating TINYINT NOT NULL CHECK (rating BETWEEN 1 AND 5),
title VARCHAR(200),
content TEXT NOT NULL,
is_photo_review BOOLEAN DEFAULT FALSE,
helpful_count INT DEFAULT 0 COMMENT '๋์๋จ ์',
admin_reply TEXT COMMENT '๊ด๋ฆฌ์ ๋ต๋ณ',
admin_replied_at TIMESTAMP NULL,
is_visible BOOLEAN DEFAULT TRUE,
is_best BOOLEAN DEFAULT FALSE COMMENT '๋ฒ ์คํธ ๋ฆฌ๋ทฐ ์ฌ๋ถ',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id),
FOREIGN KEY (member_id) REFERENCES members(member_id),
FOREIGN KEY (order_item_id) REFERENCES order_items(order_item_id),
INDEX idx_product (product_id),
INDEX idx_member (member_id),
INDEX idx_rating (rating),
INDEX idx_created_at (created_at),
UNIQUE KEY unique_review (order_item_id) -- ํ ์ฃผ๋ฌธ ์ํ๋น ํ๋์ ๋ฆฌ๋ทฐ๋ง
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ๋ฆฌ๋ทฐ ์ด๋ฏธ์ง ํ
์ด๋ธ
CREATE TABLE review_images (
image_id BIGINT PRIMARY KEY AUTO_INCREMENT,
review_id BIGINT NOT NULL,
image_url VARCHAR(500) NOT NULL,
display_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (review_id) REFERENCES product_reviews(review_id) ON DELETE CASCADE,
INDEX idx_review (review_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ๊ตฌ๋งค ํ์ธ ํ์๋ง ๋ฆฌ๋ทฐ ์์ฑ ๊ฐ๋ฅํ๋๋ก ์ ํ
โข ํฌํ ๋ฆฌ๋ทฐ ์์ฑ ์ ์ถ๊ฐ ํฌ์ธํธ ์ง๊ธ์ผ๋ก ์ ๋
โข ๋ฒ ์คํธ ๋ฆฌ๋ทฐ๋ ์๋ ์ ์ (ํ์ , ๋์๋จ ์, ๊ธธ์ด ๋ฑ ๊ณ ๋ ค)
โข ๋ฆฌ๋ทฐ ์์ฑ ์ ์ํ์ rating_average, review_count ์๋ ์ ๋ฐ์ดํธ
โข ๋ถ์ ์ ํ ๋ฆฌ๋ทฐ ์ ๊ณ ๊ธฐ๋ฅ ์ถ๊ฐ ๊ณ ๋ ค
๊ด์ฌ ์ํ์ ์ ์ฅํ๋ ์์๋ฆฌ์คํธ! ๊ฐ๋จํ์ง๋ง ์ ํ์จ์ ๋์ด๋ ๋ฐ ํจ๊ณผ์ ์ด์ผ. โค๏ธ
CREATE TABLE wishlists (
wishlist_id BIGINT PRIMARY KEY AUTO_INCREMENT,
member_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
INDEX idx_member (member_id),
INDEX idx_product (product_id),
UNIQUE KEY unique_wishlist (member_id, product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ํฌ์ธํธ๋ ๊ณ ๊ฐ ์ถฉ์ฑ๋๋ฅผ ๋์ด๋ ํต์ฌ ๊ธฐ๋ฅ์ด์ผ! ์ ๋ฆฝ๊ณผ ์ฌ์ฉ ๋ด์ญ์ ์ ํํ ๊ด๋ฆฌํด์ผ ํด. ๐ฐ
CREATE TABLE point_histories (
history_id BIGINT PRIMARY KEY AUTO_INCREMENT,
member_id BIGINT NOT NULL,
point_type ENUM('EARN', 'USE', 'CANCEL', 'EXPIRE') NOT NULL,
point_amount INT NOT NULL COMMENT 'ํฌ์ธํธ ๊ธ์ก (์์: ์ ๋ฆฝ, ์์: ์ฌ์ฉ)',
point_balance INT NOT NULL COMMENT '๋ณ๋ ํ ์์ก',
reason VARCHAR(100) NOT NULL COMMENT '์ ๋ฆฝ/์ฌ์ฉ ์ฌ์ ',
reference_type VARCHAR(50) COMMENT '์ฐธ์กฐ ํ์
(ORDER, REVIEW, EVENT)',
reference_id BIGINT COMMENT '์ฐธ์กฐ ID',
expire_date DATE COMMENT 'ํฌ์ธํธ ๋ง๋ฃ์ผ',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES members(member_id),
INDEX idx_member (member_id),
INDEX idx_created_at (created_at),
INDEX idx_expire_date (expire_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
โข ํฌ์ธํธ ์์ก์ members ํ ์ด๋ธ๊ณผ point_histories ํ ์ด๋ธ ์์ชฝ์์ ๊ด๋ฆฌ
โข ํธ๋์ญ์ ์ผ๋ก ๋ฌถ์ด์ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋ณด์ฅ ํ์
โข ํฌ์ธํธ ๋ง๋ฃ ์ฒ๋ฆฌ๋ ๋ฐฐ์น ์์ ์ผ๋ก ์ ๊ธฐ ์คํ
โข ์ฃผ๋ฌธ ์ทจ์ ์ ์ฌ์ฉํ ํฌ์ธํธ ์๋ ๋ณต๊ตฌ
โข ํฌ์ธํธ ๋ถ์ ์ฌ์ฉ ๋ฐฉ์ง๋ฅผ ์ํ ๋ก์ง ํ์
๐ ์ค์ ์ฟผ๋ฆฌ ์์
์ด๋ก ๋ง ์์์๋ ์์ฉ์์ง! ์ค์ ๋ก ์์ฃผ ์ฌ์ฉํ๋ ์ฟผ๋ฆฌ๋ค์ ์์ ๋ก ๋ง๋ค์ด๋ดค์ด. ์ค๋ฌด์์ ๋ฐ๋ก ์จ๋จน์ ์ ์์ ๊ฑฐ์ผ! ๐ช
-- ์นดํ
๊ณ ๋ฆฌ๋ณ ์ํ ๋ชฉ๋ก (์ธ๊ธฐ์, ํ์ด์ง)
SELECT
p.product_id,
p.product_name,
p.price,
p.discount_price,
COALESCE(p.discount_price, p.price) AS final_price,
p.rating_average,
p.review_count,
p.sales_count,
pi.image_url AS thumbnail
FROM products p
LEFT JOIN product_images pi ON p.product_id = pi.product_id
AND pi.image_type = 'MAIN'
WHERE p.category_id = 10
AND p.is_display = TRUE
AND p.is_soldout = FALSE
ORDER BY p.sales_count DESC, p.created_at DESC
LIMIT 20 OFFSET 0; -- ํ์ด์ง๋น 20๊ฐ, 1ํ์ด์ง
-- ๊ฐ๊ฒฉ๋๋ณ ํํฐ๋ง
SELECT
p.product_id,
p.product_name,
COALESCE(p.discount_price, p.price) AS final_price
FROM products p
WHERE p.category_id = 10
AND COALESCE(p.discount_price, p.price) BETWEEN 10000 AND 50000
AND p.is_display = TRUE
ORDER BY final_price ASC;
-- ์ ๋ฌธ ๊ฒ์ (์ํ๋ช
, ์ค๋ช
)
SELECT
p.product_id,
p.product_name,
p.price,
MATCH(p.product_name, p.description) AGAINST('์
์ธ ' IN NATURAL LANGUAGE MODE) AS relevance
FROM products p
WHERE MATCH(p.product_name, p.description) AGAINST('์
์ธ ' IN NATURAL LANGUAGE MODE)
AND p.is_display = TRUE
ORDER BY relevance DESC, p.sales_count DESC
LIMIT 20;
-- ์ฃผ๋ฌธ ์์ฑ (ํธ๋์ญ์
ํ์!)
START TRANSACTION;
-- 1. ์ฃผ๋ฌธ ์์ฑ
INSERT INTO orders (
order_number, member_id, order_status, payment_method,
total_product_price, total_discount_amount, delivery_fee,
total_payment_amount, used_point,
recipient_name, recipient_phone, postal_code,
address_line1, address_line2
) VALUES (
'ORD20240115001234', 123, 'PENDING', 'CARD',
50000, 5000, 3000, 48000, 0,
'ํ๊ธธ๋', '010-1234-5678', '12345',
'์์ธ์ ๊ฐ๋จ๊ตฌ', 'ํ
ํค๋๋ก 123'
);
SET @order_id = LAST_INSERT_ID();
-- 2. ์ฃผ๋ฌธ ์์ธ ์์ฑ ๋ฐ ์ฌ๊ณ ์ฐจ๊ฐ
INSERT INTO order_items (
order_id, product_id, product_name, product_code,
quantity, unit_price, discount_amount, total_price
)
SELECT
@order_id,
p.product_id,
p.product_name,
p.product_code,
c.quantity,
COALESCE(p.discount_price, p.price),
0,
COALESCE(p.discount_price, p.price) * c.quantity
FROM cart_items c
JOIN products p ON c.product_id = p.product_id
WHERE c.member_id = 123 AND c.is_selected = TRUE;
-- 3. ์ฌ๊ณ ์ฐจ๊ฐ (์์์ ์
๋ฐ์ดํธ)
UPDATE products p
JOIN cart_items c ON p.product_id = c.product_id
SET p.stock_quantity = p.stock_quantity - c.quantity,
p.sales_count = p.sales_count + c.quantity
WHERE c.member_id = 123
AND c.is_selected = TRUE
AND p.stock_quantity >= c.quantity;
-- 4. ์ฌ๊ณ ๋ถ์กฑ ์ฒดํฌ
SELECT COUNT(*) INTO @stock_check
FROM cart_items c
JOIN products p ON c.product_id = p.product_id
WHERE c.member_id = 123
AND c.is_selected = TRUE
AND p.stock_quantity < 0;
-- ์ฌ๊ณ ๋ถ์กฑ ์ ๋กค๋ฐฑ
IF @stock_check > 0 THEN
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '์ฌ๊ณ ๊ฐ ๋ถ์กฑํฉ๋๋ค';
END IF;
-- 5. ํฌ์ธํธ ์ฌ์ฉ (์ฌ์ฉํ ๊ฒฝ์ฐ)
-- UPDATE members SET point_balance = point_balance - ์ฌ์ฉํฌ์ธํธ
-- INSERT INTO point_histories ...
-- 6. ์ฅ๋ฐ๊ตฌ๋ ๋น์ฐ๊ธฐ
DELETE FROM cart_items
WHERE member_id = 123 AND is_selected = TRUE;
COMMIT;
-- ์ผ๋ณ ๋งค์ถ ํต๊ณ
SELECT
DATE(created_at) AS order_date,
COUNT(*) AS order_count,
SUM(total_payment_amount) AS total_sales,
AVG(total_payment_amount) AS avg_order_value,
COUNT(DISTINCT member_id) AS unique_customers
FROM orders
WHERE order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
AND created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY DATE(created_at)
ORDER BY order_date DESC;
-- ์นดํ
๊ณ ๋ฆฌ๋ณ ๋งค์ถ ์์
SELECT
c.category_name,
COUNT(DISTINCT oi.order_id) AS order_count,
SUM(oi.quantity) AS total_quantity,
SUM(oi.total_price) AS total_sales
FROM order_items oi
JOIN products p ON oi.product_id = p.product_id
JOIN categories c ON p.category_id = c.category_id
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
AND o.created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY c.category_id, c.category_name
ORDER BY total_sales DESC
LIMIT 10;
-- ๋ฒ ์คํธ์
๋ฌ ์ํ (์ต๊ทผ 30์ผ)
SELECT
p.product_id,
p.product_name,
p.price,
SUM(oi.quantity) AS total_sold,
SUM(oi.total_price) AS total_revenue,
p.rating_average,
p.review_count
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
AND o.created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY p.product_id
ORDER BY total_sold DESC
LIMIT 20;
-- ํ์ ๋ฑ๊ธ๋ณ ๊ตฌ๋งค ํจํด
SELECT
m.member_grade,
COUNT(DISTINCT m.member_id) AS member_count,
COUNT(o.order_id) AS total_orders,
ROUND(COUNT(o.order_id) / COUNT(DISTINCT m.member_id), 2) AS avg_orders_per_member,
SUM(o.total_payment_amount) AS total_sales,
ROUND(AVG(o.total_payment_amount), 0) AS avg_order_value
FROM members m
LEFT JOIN orders o ON m.member_id = o.member_id
AND o.order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
AND o.created_at >= DATE_SUB(CURDATE(), INTERVAL 90 DAY)
GROUP BY m.member_grade
ORDER BY total_sales DESC;
-- RFM ๋ถ์ (Recency, Frequency, Monetary)
SELECT
m.member_id,
m.email,
m.name,
DATEDIFF(CURDATE(), MAX(o.created_at)) AS recency_days,
COUNT(o.order_id) AS frequency,
SUM(o.total_payment_amount) AS monetary
FROM members m
LEFT JOIN orders o ON m.member_id = o.member_id
AND o.order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
WHERE m.is_active = TRUE
GROUP BY m.member_id
HAVING frequency > 0
ORDER BY monetary DESC, frequency DESC, recency_days ASC;
-- ์ดํ ์ํ ๊ณ ๊ฐ (์ต๊ทผ 90์ผ ๊ตฌ๋งค ์์, ๊ณผ๊ฑฐ ๊ตฌ๋งค ์ด๋ ฅ ์์)
SELECT
m.member_id,
m.email,
m.name,
m.total_purchase_amount,
MAX(o.created_at) AS last_order_date,
DATEDIFF(CURDATE(), MAX(o.created_at)) AS days_since_last_order
FROM members m
JOIN orders o ON m.member_id = o.member_id
WHERE o.order_status IN ('PAID', 'PREPARING', 'SHIPPING', 'DELIVERED')
GROUP BY m.member_id
HAVING days_since_last_order > 90
ORDER BY m.total_purchase_amount DESC
LIMIT 100;
๐ก๏ธ ๋ฐ์ดํฐ ๋ฐฑ์ ๋ฐ ๋ณต๊ตฌ ์ ๋ต
์๋ฌด๋ฆฌ ์ ์ค๊ณํด๋ ์ฅ์ ๋ ๋ฐ์ํ ์ ์์ด! ๋ฐ์ดํฐ ์์ค์ ๋ฐฉ์งํ๊ธฐ ์ํ ๋ฐฑ์ ์ ๋ต์ด ํ์์ผ. ๐
1. ์ ๊ธฐ ๋ฐฑ์ (Full Backup)
โข ๋งค์ผ ์๋ฒฝ ์๊ฐ๋์ ์ ์ฒด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์
โข ์ต์ 7์ผ์น ๋ฐฑ์ ํ์ผ ๋ณด๊ด
โข ์๋ณ ๋ฐฑ์ ์ 1๋ ๊ฐ ๋ณด๊ด
2. ์ฆ๋ถ ๋ฐฑ์ (Incremental Backup)
โข ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ง ๋ฐฑ์ (๋์คํฌ ๊ณต๊ฐ ์ ์ฝ)
โข ๋งค ์๊ฐ๋ง๋ค ์คํ
3. ๋ฐ์ด๋๋ฆฌ ๋ก๊ทธ ๋ฐฑ์
โข MySQL์ ๋ฐ์ด๋๋ฆฌ ๋ก๊ทธ๋ฅผ ๋ณ๋ ์ ์ฅ
โข ํน์ ์์ ์ผ๋ก ๋ณต๊ตฌ ๊ฐ๋ฅ (Point-in-Time Recovery)
4. ๋ณต์ ์๋ฒ ์ด์
โข Master-Slave ๊ตฌ์กฐ๋ก ์ค์๊ฐ ๋ณต์
โข ์ฅ์ ๋ฐ์ ์ ์ฆ์ ์ ํ ๊ฐ๋ฅ
-- MySQL ๋ฐฑ์
๋ช
๋ น์ด ์์
-- ์ ์ฒด ๋ฐฑ์
mysqldump -u root -p --all-databases --single-transaction \
--routines --triggers --events > backup_$(date +%Y%m%d).sql
-- ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ง ๋ฐฑ์
mysqldump -u root -p shopping_mall --single-transaction \
--routines --triggers > shopping_mall_$(date +%Y%m%d).sql
-- ๋ณต๊ตฌ
mysql -u root -p shopping_mall < backup_20240115.sql
-- ๋ฐ์ด๋๋ฆฌ ๋ก๊ทธ ํ์ฑํ (my.cnf)
[mysqld]
log-bin=mysql-bin
server-id=1
binlog_format=ROW
expire_logs_days=7
๐ ํ์ฅ ๊ฐ๋ฅํ ์ํคํ ์ฒ
์ฒ์์ ์๊ฒ ์์ํด๋ ์ฑ๊ณตํ๋ฉด ํธ๋ํฝ์ด ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํ ์ ์์ด! ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ณ ๋ คํ๋ ๊ฒ ์ค์ํด. ๐
์ผํ๋ชฐ์ ์กฐํ(์ฝ๊ธฐ)๊ฐ ์ฃผ๋ฌธ(์ฐ๊ธฐ)๋ณด๋ค ํจ์ฌ ๋ง์. ๊ทธ๋์ ์ฝ๊ธฐ์ ์ฐ๊ธฐ๋ฅผ ๋ถ๋ฆฌํ๋ฉด ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋ผ! ๐ฏ
Master DB (์ฐ๊ธฐ ์ ์ฉ)
โข INSERT, UPDATE, DELETE ์ฒ๋ฆฌ
โข ์ฃผ๋ฌธ, ํ์๊ฐ์ , ์ํ ๋ฑ๋ก ๋ฑ
Slave DB (์ฝ๊ธฐ ์ ์ฉ)
โข SELECT ์ฒ๋ฆฌ
โข ์ํ ๋ชฉ๋ก, ์์ธ ์กฐํ ๋ฑ
โข ์ฌ๋ฌ ๋์ Slave๋ก ๋ถํ ๋ถ์ฐ ๊ฐ๋ฅ
๋ณต์ ์ง์ฐ(Replication Lag) ์ฃผ์
โข Master์์ Slave๋ก ๋ฐ์ดํฐ ๋ณต์ ์ ์ฝ๊ฐ์ ์๊ฐ ์์
โข ์ค์๊ฐ์ฑ์ด ์ค์ํ ๋ฐ์ดํฐ๋ Master์์ ์กฐํ
๋ฐ์ดํฐ๊ฐ ์ ๋ง ๋ง์์ง๋ฉด ํ ๋์ DB๋ก๋ ๊ฐ๋น์ด ์ ๋ผ. ๊ทธ๋ด ๋ ์ค๋ฉ์ ๊ณ ๋ คํด์ผ ํด! ๐ช
1. ์ํ ์ค๋ฉ (Horizontal Sharding)
โข ํ์ ID ๊ธฐ์ค์ผ๋ก ๋ถํ
โข ์: ID 1~100๋ง โ DB1, 101๋ง~200๋ง โ DB2
2. ์์ง ์ค๋ฉ (Vertical Sharding)
โข ๊ธฐ๋ฅ๋ณ๋ก DB ๋ถ๋ฆฌ
โข ์: ํ์DB, ์ํDB, ์ฃผ๋ฌธDB ๋ถ๋ฆฌ
3. ์ง์ญ๋ณ ์ค๋ฉ
โข ๊ธ๋ก๋ฒ ์๋น์ค์ ๊ฒฝ์ฐ ์ง์ญ๋ณ๋ก DB ๋ถ๋ฆฌ
โข ์: ํ๊ตญDB, ๋ฏธ๊ตญDB, ์ ๋ฝDB
โข JOIN ์ฟผ๋ฆฌ๊ฐ ์ด๋ ค์์ง (์ฌ๋ฌ ์ค๋์ ๊ฑธ์น JOIN ๋ถ๊ฐ)
โข ํธ๋์ญ์ ๊ด๋ฆฌ๊ฐ ๋ณต์กํด์ง
โข ์ค๋ ํค ์ ํ์ด ๋งค์ฐ ์ค์ (์ฌ๋ถ๋ฐฐ ์ด๋ ค์)
โข ์ฒ์๋ถํฐ ์ค๋ฉํ์ง ๋ง๊ณ , ์ ๋ง ํ์ํ ๋๋ง!
DB ๋ถํ๋ฅผ ์ค์ด๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ์บ์ฑ์ด์ผ! Redis๋ Memcached๋ฅผ ํ์ฉํ๋ฉด ์๋ต ์๋๊ฐ ์์ญ ๋ฐฐ ๋นจ๋ผ์ ธ. โก
1. ์ํ ์ ๋ณด
โข ์ํ ์์ธ ์ ๋ณด (๋ณ๊ฒฝ ๋น๋ ๋ฎ์)
โข TTL: 1์๊ฐ
2. ์นดํ ๊ณ ๋ฆฌ ๋ชฉ๋ก
โข ์นดํ ๊ณ ๋ฆฌ ํธ๋ฆฌ ๊ตฌ์กฐ
โข TTL: 24์๊ฐ
3. ๋ฒ ์คํธ์ ๋ฌ ๋ชฉ๋ก
โข ์ธ๊ธฐ ์ํ ์์
โข TTL: 10๋ถ
4. ํ์ ์ธ์
โข ๋ก๊ทธ์ธ ์ ๋ณด
โข TTL: 30๋ถ
5. ์ฅ๋ฐ๊ตฌ๋
โข ๋นํ์ ์ฅ๋ฐ๊ตฌ๋
โข TTL: 7์ผ
๐ก ์ค๋ฌด ํ & ๋ฒ ์คํธ ํ๋ํฐ์ค
๋ง์ง๋ง์ผ๋ก ๋ด๊ฐ ์ค๋ฌด์์ ๊ฒฝํํ ๋ ธํ์ฐ๋ค์ ๊ณต์ ํ ๊ฒ! ์ด๊ฒ๋ง ์์๋ ๋ง์ ์ํ์ฐฉ์ค๋ฅผ ์ค์ผ ์ ์์ ๊ฑฐ์ผ. ๐
โ ๋ช ๋ช ๊ท์น
โข ํ ์ด๋ธ๋ช : ๋ณต์ํ ์ฌ์ฉ (products, orders)
โข ์ปฌ๋ผ๋ช : snake_case ์ฌ์ฉ (product_name, created_at)
โข ์ธ๋ํค: ์ฐธ์กฐ ํ ์ด๋ธ๋ช _id (member_id, product_id)
โข ์ธ๋ฑ์ค: idx_์ปฌ๋ผ๋ช (idx_email, idx_created_at)
โ ๋ฐ์ดํฐ ํ์ ์ ํ
โข ๊ธ์ก: DECIMAL(์ ํํ ๊ณ์ฐ ํ์)
โข ๋ ์ง/์๊ฐ: TIMESTAMP (์๊ฐ๋ ๊ณ ๋ ค) ๋๋ DATETIME
โข ์ํ๊ฐ: ENUM (๊ณ ์ ๋ ๊ฐ) ๋๋ TINYINT
โข ํ ์คํธ: VARCHAR(๊ธธ์ด ์ ํ) ๋๋ TEXT
โข Boolean: BOOLEAN ๋๋ TINYINT(1)
โ ์ ์ฝ ์กฐ๊ฑด
โข PRIMARY KEY: ๋ชจ๋ ํ ์ด๋ธ์ ํ์
โข FOREIGN KEY: ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๋ณด์ฅ
โข UNIQUE: ์ค๋ณต ๋ฐฉ์ง (์ด๋ฉ์ผ, ์ฃผ๋ฌธ๋ฒํธ ๋ฑ)
โข NOT NULL: ํ์ ๊ฐ ์ง์
โข DEFAULT: ๊ธฐ๋ณธ๊ฐ ์ค์
โ ์ธ๋ฑ์ค
โข WHERE ์ ์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
โข JOIN ์กฐ๊ฑด ์ปฌ๋ผ
โข ORDER BY ์ปฌ๋ผ
โข ๋ณตํฉ ์ธ๋ฑ์ค๋ ์ ํ๋๊ฐ ๋์ ์ปฌ๋ผ์ ์์
โ ๋ณด์
โข ๋น๋ฐ๋ฒํธ๋ ํด์ ์ ์ฅ (bcrypt, Argon2)
โข ๊ฐ์ธ์ ๋ณด๋ ์ํธํ ๊ณ ๋ ค
โข SQL Injection ๋ฐฉ์ง (Prepared Statement)
โข ์ต์ ๊ถํ ์์น (DB ์ฌ์ฉ์ ๊ถํ ์ ํ)
โข SELECT * ์ฌ์ฉ ์์ , ํ์ํ ์ปฌ๋ผ๋ง ์กฐํ
โข N+1 ์ฟผ๋ฆฌ ๋ฌธ์ ํด๊ฒฐ (JOIN ๋๋ IN ์ฌ์ฉ)
โข ํ์ด์ง ์ฒ๋ฆฌ ํ์ (LIMIT, OFFSET)
โข ์ฌ๋ก์ฐ ์ฟผ๋ฆฌ ๋ก๊ทธ ๋ชจ๋ํฐ๋ง
โข EXPLAIN์ผ๋ก ์คํ ๊ณํ ํ์ธ
โข ์ ์ ํ ์ธ๋ฑ์ค ์์ฑ
โข ์บ์ฑ ํ์ฉ
โข ์ปค๋ฅ์ ํ ์ค์
โ ์ค์ 1: ๊ณผ๋ํ ์ ๊ทํ
โ ์กฐํ ์ฑ๋ฅ ์ ํ, ๋ณต์กํ JOIN
โ ํด๊ฒฐ: ์ ์ ํ ์ญ์ ๊ทํ๋ก ๊ท ํ ์ ์ง
โ ์ค์ 2: ์ธ๋ฑ์ค ๋ถ์กฑ ๋๋ ๊ณผ๋ค
โ ์กฐํ ๋๋ฆผ ๋๋ ์ฐ๊ธฐ ๋๋ฆผ
โ ํด๊ฒฐ: ์ค์ ์ฟผ๋ฆฌ ํจํด ๋ถ์ ํ ์ต์ ํ
โ ์ค์ 3: ํธ๋์ญ์ ๋ฏธ์ฌ์ฉ
โ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋ฌธ์
โ ํด๊ฒฐ: ๊ด๋ จ ์์ ์ ๋ฐ๋์ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ๊ธฐ
โ ์ค์ 4: ๋์์ฑ ์ ์ด ๋ฏธํก
โ ์ฌ๊ณ ๋ง์ด๋์ค, ์ค๋ณต ๊ฒฐ์ ๋ฑ
โ ํด๊ฒฐ: ๋ฝ(Lock) ๋๋ ์์์ ์ ๋ฐ์ดํธ ์ฌ์ฉ
โ ์ค์ 5: ๋ฐฑ์ ์ ๋ต ๋ถ์ฌ
โ ๋ฐ์ดํฐ ์์ค ์ ๋ณต๊ตฌ ๋ถ๊ฐ
โ ํด๊ฒฐ: ์ ๊ธฐ ๋ฐฑ์ ๋ฐ ๋ณต๊ตฌ ํ ์คํธ
๐ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ฌ๊ธฐ๊น์ง ์ฝ๋๋ผ ์๊ณ ํ์ด! ๐
์ผํ๋ชฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ๋ ์ ๋ง ๋ณต์กํ๊ณ ๊ณ ๋ คํ ๊ฒ ๋ง์ง? ํ์ง๋ง ํ ๋ฒ ์ ๋๋ก ์ค๊ณํด๋๋ฉด ๋์ค์ ์ ๋ง ํธํด. ๋ฐ๋๋ก ์ฒ์์ ๋์ถฉ ๋ง๋ค๋ฉด ๋์ค์ ์์ฒญ๋ ๊ณ ์์ ํ๊ฒ ๋ผ... (๊ฒฝํ๋ด ๐
)
์ค๋ ๋ค๋ฃฌ ๋ด์ฉ์ ์ ๋ฆฌํด๋ณด๋ฉด:
1. ๊ธฐ๋ณธ ์์น
โข ์ ๊ทํ์ ์ญ์ ๊ทํ์ ๊ท ํ
โข ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ ์ค๊ณ
โข ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ ๋ณด์ฅ
2. ํต์ฌ ํ
์ด๋ธ
โข ํ์ ๊ด๋ฆฌ (members, member_addresses)
โข ์ํ ๊ด๋ฆฌ (products, categories, product_options)
โข ์ฃผ๋ฌธ ๊ด๋ฆฌ (orders, order_items, payments)
3. ๋ถ๊ฐ ๊ธฐ๋ฅ
โข ์ฟ ํฐ, ๋ฆฌ๋ทฐ, ์์๋ฆฌ์คํธ, ํฌ์ธํธ
โข ๊ฐ ๊ธฐ๋ฅ๋ณ ์ต์ ํ๋ ํ
์ด๋ธ ๊ตฌ์กฐ
4. ์ฑ๋ฅ ์ต์ ํ
โข ์ธ๋ฑ์ค ์ ๋ต
โข ์ฟผ๋ฆฌ ์ต์ ํ
โข ๋์์ฑ ์ ์ด
โข ์บ์ฑ ํ์ฉ
5. ํ์ฅ์ฑ
โข ์ฝ๊ธฐ/์ฐ๊ธฐ ๋ถ๋ฆฌ
โข ์ค๋ฉ
โข ๋ฐฑ์
๋ฐ ๋ณต๊ตฌ
์ผํ๋ชฐ ๊ฐ๋ฐ์ด ์ฒ์์ด๋ผ ๋ง๋งํ๋ค๋ฉด? ์ฌ๋ฅ๋ท์์ ์ค๋ฌด ๊ฒฝํ์ด ํ๋ถํ ๊ฐ๋ฐ์๋ค์๊ฒ 1:1 ๋ฉํ ๋ง์ ๋ฐ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ!
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ๋ถํฐ ์ค์ ๊ตฌํ๊น์ง, ํ๋ก์ ํธ ์ ๋ฐ์ ๊ฑธ์น ๋์์ ๋ฐ์ ์ ์์ด. ํผ์ ๊ณ ๋ฏผํ์ง ๋ง๊ณ ์ฌ๋ฅ๋ท์ ์ ๋ฌธ๊ฐ๋ค๊ณผ ํจ๊ป ์ฑ์ฅํด๋ณด์! ๐ช
์ค๋ฌด์์๋ ์ด๋ก ๋ง์ผ๋ก๋ ๋ถ์กฑํด. ์ง์ ๋ง๋ค์ด๋ณด๊ณ , ์ค์ํ๊ณ , ๊ฐ์ ํ๋ฉด์ ๋ฐฐ์ฐ๋ ๊ฒ ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ์ด์ผ.
์ฒ์์ ์๋ฒฝํ์ง ์์๋ ๊ด์ฐฎ์! ์๊ฒ ์์ํด์ ์ ์ง์ ์ผ๋ก ๊ฐ์ ํด๋๊ฐ๋ฉด ๋ผ. ์ค์ํ ๊ฑด ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ก ์์ํ๋ ๊ฑฐ์ผ. ๊ทธ๋์ผ ๋์ค์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ฑฐ๋ ์์ ํ ๋ ์ ์ฒด๋ฅผ ๋ค์์ง ์์๋ ๋๊ฑฐ๋ ! ๐ฏ
๊ทธ๋ฆฌ๊ณ ํญ์ ๊ธฐ์ตํด! ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋๊ณผ ์ง๊ฒฐ๋๋ ๋ถ๋ถ์ด์ผ. ์ฃผ๋ฌธ, ๊ฒฐ์ , ์ฌ๊ณ ... ์ด๋ฐ ์ค์ํ ๋ฐ์ดํฐ๋ค์ด ์ ์ฅ๋๋ ๊ณณ์ด๋๊น ๋ณด์๊ณผ ์ ํฉ์ฑ์ ํนํ ์ ๊ฒฝ ์จ์ผ ํด! ๐
๋ง์ง๋ง์ผ๋ก, ์ด ๊ธ์ด ๋์์ด ๋์๋ค๋ฉด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด๊ณ , ์์ ๋ง์ ๋
ธํ์ฐ๋ฅผ ์์๊ฐ๊ธธ ๋ฐ๋ผ! ๊ถ๊ธํ ์ ์ด ์์ผ๋ฉด ์ธ์ ๋ ์ปค๋ฎค๋ํฐ์์ ๋ฌผ์ด๋ด. ์ฐ๋ฆฌ ๋ชจ๋ ํจ๊ป ์ฑ์ฅํ๋ ๊ฑฐ๋๊น! ๐
ํ์ดํ
! ๋ฉ์ง ์ผํ๋ชฐ ๋ง๋ค์ด๋ณด์! ๐ชโจ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.