๐Ÿ—„๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๐ŸŒฟ ์ค‘๊ธ‰

PostgreSQL ์‹ค์ „

PostgreSQL ๊ณ ๊ธ‰ ์ฟผ๋ฆฌ์™€ ์ตœ์ ํ™”

โฑ๏ธ 8์‹œ๊ฐ„ ๐Ÿ‘๏ธ 24 ์กฐํšŒ
๐Ÿ“– ๊ฐ•์ขŒ ๋‚ด์šฉ
# PostgreSQL ์‹ค์ „ ๊ฐ€์ด๋“œ

## ํ•™์Šต ๋ชฉํ‘œ
๊ฐ•๋ ฅํ•œ ์˜คํ”ˆ์†Œ์Šค ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค PostgreSQL์„ ๋งˆ์Šคํ„ฐํ•ฉ๋‹ˆ๋‹ค.

## 1. PostgreSQL์ด๋ž€?
๊ฐ€์žฅ ์ง„๋ณด๋œ ์˜คํ”ˆ์†Œ์Šค ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ž…๋‹ˆ๋‹ค.
- ACID ์™„๋ฒฝ ์ง€์›
- JSON/JSONB ๋„ค์ดํ‹ฐ๋ธŒ ์ง€์›
- ๊ฐ•๋ ฅํ•œ ํ™•์žฅ์„ฑ
- ํ’๋ถ€ํ•œ ๋ฐ์ดํ„ฐ ํƒ€์ž…

## 2. ์„ค์น˜ ๋ฐ ์ ‘์†
Docker:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=password postgres

์ ‘์†:
psql -U postgres -h localhost
psql -d mydb -U myuser

๊ธฐ๋ณธ ๋ช…๋ น:
\l - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชฉ๋ก
\c mydb - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ „ํ™˜
\dt - ํ…Œ์ด๋ธ” ๋ชฉ๋ก
\d users - ํ…Œ์ด๋ธ” ๊ตฌ์กฐ
\q - ์ข…๋ฃŒ

## 3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ฆฌ
CREATE DATABASE mydb;
DROP DATABASE mydb;
CREATE USER myuser WITH PASSWORD "password";
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;

## 4. ํ…Œ์ด๋ธ” ์ƒ์„ฑ
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
age INTEGER CHECK (age >= 0),
balance DECIMAL(10,2) DEFAULT 0,
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
content TEXT,
tags TEXT[],
published_at TIMESTAMP
);

## 5. ๊ธฐ๋ณธ CRUD
INSERT:
INSERT INTO users (name, email, age) VALUES ("Kim", "kim@test.com", 25);
INSERT INTO users (name, email) VALUES ("Lee", "lee@test.com") RETURNING id;

SELECT:
SELECT * FROM users;
SELECT name, email FROM users WHERE age >= 20;
SELECT * FROM users ORDER BY created_at DESC LIMIT 10 OFFSET 20;

UPDATE:
UPDATE users SET age = 26 WHERE name = "Kim";
UPDATE users SET age = age + 1 RETURNING *;

DELETE:
DELETE FROM users WHERE id = 1;

## 6. JSON/JSONB ํ™œ์šฉ
์ €์žฅ:
INSERT INTO users (name, metadata) VALUES ("Kim",
{"address": {"city": "Seoul"}, "tags": ["vip", "premium"]}
);

์กฐํšŒ:
SELECT metadata->"address"->"city" FROM users;
SELECT metadata->>"address" FROM users;
SELECT * FROM users WHERE metadata @> {"tags": ["vip"]};
SELECT * FROM users WHERE metadata ? "address";

์ˆ˜์ •:
UPDATE users SET metadata = jsonb_set(metadata, "{address,zip}", "12345");

## 7. ๋ฐฐ์—ด ํƒ€์ž…
์ €์žฅ:
INSERT INTO posts (title, tags) VALUES ("Hello", ARRAY["tech", "news"]);

์กฐํšŒ:
SELECT * FROM posts WHERE "tech" = ANY(tags);
SELECT * FROM posts WHERE tags @> ARRAY["tech"];
SELECT unnest(tags) FROM posts;

## 8. ์ธ๋ฑ์Šค
๊ธฐ๋ณธ ์ธ๋ฑ์Šค:
CREATE INDEX idx_users_email ON users(email);
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);

๋ณตํ•ฉ ์ธ๋ฑ์Šค:
CREATE INDEX idx_posts_user_date ON posts(user_id, published_at DESC);

JSONB ์ธ๋ฑ์Šค:
CREATE INDEX idx_users_metadata ON users USING GIN(metadata);

๋ถ€๋ถ„ ์ธ๋ฑ์Šค:
CREATE INDEX idx_active_users ON users(email) WHERE active = true;

## 9. JOIN
INNER JOIN:
SELECT u.name, p.title FROM users u INNER JOIN posts p ON u.id = p.user_id;

LEFT JOIN:
SELECT u.name, COUNT(p.id) FROM users u LEFT JOIN posts p ON u.id = p.user_id GROUP BY u.id;

## 10. CTE์™€ ์œˆ๋„์šฐ ํ•จ์ˆ˜
CTE:
WITH active_users AS (
SELECT * FROM users WHERE last_login > NOW() - INTERVAL "30 days"
)
SELECT * FROM active_users WHERE age > 20;

์œˆ๋„์šฐ ํ•จ์ˆ˜:
SELECT name, age, RANK() OVER (ORDER BY age DESC) FROM users;
SELECT name, age, AVG(age) OVER () as avg_age FROM users;
SELECT name, created_at, LAG(created_at) OVER (ORDER BY created_at) as prev FROM users;

## 11. ํŠธ๋žœ์žญ์…˜
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- ์—๋Ÿฌ ์‹œ
ROLLBACK;

๊ฒฉ๋ฆฌ ์ˆ˜์ค€:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

## 12. ๋ฐฑ์—… ๋ฐ ๋ณต์›
๋ฐฑ์—…:
pg_dump -U postgres mydb > backup.sql
pg_dump -U postgres -Fc mydb > backup.dump

๋ณต์›:
psql -U postgres mydb < backup.sql
pg_restore -U postgres -d mydb backup.dump

## ์ถ”์ฒœ ํ•™์Šต ์ˆœ์„œ
1. ๊ธฐ๋ณธ SQL ๋ฌธ๋ฒ•
2. JSON/๋ฐฐ์—ด ํƒ€์ž… ํ™œ์šฉ
3. ์ธ๋ฑ์Šค ์ „๋žต
4. ์œˆ๋„์šฐ ํ•จ์ˆ˜
5. ์„ฑ๋Šฅ ์ตœ์ ํ™”