4.7 Databases#
๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํฌ๊ฒ RDBMS
์ NoSQL(Not only SQL)
๋ก ๋๋ ์ ์์ต๋๋ค.
์ด๋ฒ ์ฑํฐ์์๋ ๊ทธ ์ค NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ข
๋ฅ ๋ฐ ํน์ง์ ๋ํด ์์๋ณด๊ณ ์ ํฉ๋๋ค.
Key-Value Store (KVS)#
Key-Value Store (KVS) ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ key - value ์์ผ๋ก ์ ์ฅํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก, ํด์ ํจ์๋ python์์์ dictionary ํ์๊ณผ ์ ์ฌํ ํํ๋ก ์ ์ฅ๋ฉ๋๋ค.
๊ธฐ๋ณธ operation#
PUT
: ์๋ก์ด key - value ์์ ์ ๋ ฅํฉ๋๋ค. (์ด๋ฏธ ํด๋น key๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ์๋ value๋ฅผ ์ ๋ฐ์ดํธ ํฉ๋๋ค.)GET
: ์ฃผ์ด์ง key์ ๋ํ value๋ฅผ ๋ฐํํฉ๋๋ค.DELETE
: ํด๋น key๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ, key - value ์์ ์ญ์ ํฉ๋๋ค.
์ฅ์ #
value์ ๋ํ data type ์ ์ฝ์ด ์์ต๋๋ค.
value์ ๊ฐ๊ฐ ๋ค๋ฅธ ์์ฑ์ ์ถ๊ฐํ ์๋ ์์ต๋๋ค.
user:123:preferences = {"language": "ko"} user:123:preferences = {"language": "en", "color": "blue"}
๋จ์ #
key์ ์ํด์๋ง ๊ฐ์ ์ฐพ์์ผ ํ๋ฏ๋ก, key ๊ฐ์ ์ ์ ์๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ด๋ฅผ ์ํด value ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ฑฐ๋, ๋ณด์กฐ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์์ต๋๋ค.
์ฌ์ฉ ์์#
์ ์ ๋ณ ์ธ์ ์ ๋ณด ์ ์ฅ (key : ์ธ์ ID / value : ์ธ์ ์ ๋ณด)
์ ์ ๋ณ ํ๋กํ ๋ฐ ๊ธฐ๋ณธ ์ค์ (key: ์ ์ ID / value : ์ ์ ์ ๋ณด)
์ ์ ๋ณ ์ถ์ฒ, ๊ด๊ณ ๋ฑ (key: ์ ์ ID / value : ํด๋น ์ ์ ์ ์ ํฉํ ์ถ์ฒ ์์ดํ ๋ฐ ๊ด๊ณ ๋ฑ)
Top 10 Key-Value Stores#
๊ทธ๋ ๋ค๋ฉด ์ด๋ค Key-Value Store๊ฐ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์๊น์?
https://db-engines.com๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Top 10 Key-Value Stores๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Redis#
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ KVS๋ ๋ฐ๋ก Redis(Remote Dictionary Server) ์
๋๋ค.
Twitter, Pinterest, stackoverflow ๋ฑ ๋ค์ํ ํ์ฌ์์๋ ์ ์ ๋ณ ์ธ์
์ ๋ณด ์ ์ฅ ์ ์ด์ฉํ๊ณ ์๋ Redis๋ ๋ค์๊ณผ ๊ฐ์ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
in-memory ๊ตฌ์กฐ
๋ฐ์ดํฐ๋ฅผ ๋์คํฌ์ ์ ์ฅํ์ง ์๊ณ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ ๋น ๋ฅธ ์๋๋ฅผ ๋ณด์ฅํ๊ฒ ๋ฉ๋๋ค.
์ถ๊ฐ๋ก ๋ฐ์ดํฐ๋ฅผ ๋์คํฌ์ ์ ์งํ ์๋ ์์ต๋๋ค.
๋น๋๊ธฐ ๋ณต์ ์ ๊ณต
๋ฐ์ดํฐ๊ฐ ๊ธฐ๋ณธ ์คํ ๋ฆฌ์ง์ ๋จผ์ ์ ์ฅ๋ ๋ค, ๋ณต์ ๋ณธ์ ์์ฑํฉ๋๋ค.
Oracle Berkeley DB#
(์ธ๊ธฐ ์๋ DB๋ ์๋์ง๋ง) ํ์ ์์ ๋ง์ด ์ฌ์ฉํ๊ณ ์๋ KVS ์ค ํ๋๋ก Oracle Berkeley DB๊ฐ ์์ต๋๋ค.
ํ์ ์์ ๊ฐ๋จํ ๋ฐ์ดํฐ ์ ์ ์ key๋ณ value ์ ๋ณด๊ฐ ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
์๋ฒ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก, sqlite์ ๊ฐ์ด ํ์ผ ํ์์ผ๋ก DB๊ฐ ์ ์ฅ๋ฉ๋๋ค.
๋ค๋ง ๋ณ๋ ฌ ์ ๊ทผ ์ ์๋๊ฐ ๋งค์ฐ ๋๋ ค์ง๋ค๋ ๋จ์ ์ด ์์ผ๋ฉฐ, ์ด๋ฌํ ์ ์ด ๋ณด์๋ RocksDB ๋ฑ์ด ์ ์๋๊ณ ์์ต๋๋ค.
Wide-Column Store (Column-family Store)#
Google BigTable ์์ ์ ๋๋ Wide-Column Store(Column-family Store)๋ row key์ column name์ ์กฐํฉ์ผ๋ก ๊ฐ์ ์ ์ฅํฉ๋๋ค.
RDBMS์ ์ ์ฌํ ํํ๋ก ๋ณผ ์ ์์ง๋ง, column์ด ์ง์ ๋์ง ์๊ณ ์์ ๋กญ๊ฒ ์
๋ ฅ๋ ์ ์๋ ํํ๋ก ๋์ด ์๋ค๋ ์ฐจ์ด์ ์ด ์์ต๋๋ค.
์ฅ์ #
row๋ง๋ค ๋ค๋ฅธ column ๊ฐ์๋ฅผ ๊ฐ์ง ์ ์๊ณ , ํ์ํ ๋๋ง๋ค ์ํ๋ column ์ถ๊ฐํ ์ ์์ต๋๋ค.
RDBMS์์๋ ํน์ column ๊ฐ์ด ์์ ๋ default value๋ฅผ ๋ฃ์ด์ผ ํ์ง๋ง,
Wide-Column Store์์๋ ํน์ column์ ๋ํด default ๊ฐ์ผ๋ก ์ฑ์ฐ์ง ์์๋ ๋ฉ๋๋ค.ํ์ํ column ์ ๋ณด๋ง ์ฐ๋ฉด ๋๊ณ ํน์ column์ ํด๋นํ๋ ๋ฐ์ดํฐ๋ง ์ฝ์ผ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ฒ๋ฆฌ ์๋๊ฐ ๋น ๋ฆ ๋๋ค.
๋จ์ #
multi-row ํธ๋์ญ์ ์ ์ง์ํ์ง ์์ต๋๋ค.
join, subquery ๋ฑ ๋ํ ์ง์ํ์ง ์์ต๋๋ค.
์ฌ์ฉ ์์#
event logging: ์ด๋ฒคํธ๋ณ ์ฌ์ฉ์ ๋ก๊ทธ ๋ด์ญ, ์ ํ๋ฆฌ์ผ์ด์ ์ค๋ฅ ๋ด์ญ ๋ฑ์ ์ ์ฅํฉ๋๋ค.
์ปจํ ์ธ ๊ด๋ฆฌ ์์คํ : ์ปจํ ์ธ ๋ณ ๋๊ธ, ๋งํฌ, ํ๊ทธ ๋ฑ์ ์ ์ฅํฉ๋๋ค.
Top 10 Wide-Column Stores#
๊ทธ๋ ๋ค๋ฉด ์ด๋ค Wide-Column Store๊ฐ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์๊น์?
Key-Value Store์ ๋ง์ฐฌ๊ฐ์ง๋ก https://db-engines.com์์ Top 10 Wide-Column Stores๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
(์ถ์ฒ: https://db-engines.com/en/ranking/wide+column+store)
Cassandra#
ํ์ด์ค๋ถ์์ ๊ฐ๋ฐ๋๊ณ ์ ํ, ๋ทํ๋ฆญ์ค, ์ฐ๋ฒ ๋ฑ์์ ์ด์ฉ์ค์ธ Cassandra๋ ์ํ์น ์ฌ๋จ์์ ๊ด๋ฆฌํ๊ณ ์๋ ์คํ์์ค์ ๋๋ค.
๋ฐ์ดํฐ๊ฐ ๋ ธ๋์ ๋ถ์ฐ๋์ด ์ ์ฅ๋๋ฏ๋ก ๋ ธ๋๋ฅผ ์ถ๊ฐํ์ฌ ์ํ์ ์ผ๋ก ํ์ฅํ ์ ์์ต๋๋ค.
Cassandra ์ ์ฉ ์ฟผ๋ฆฌ ์ธ์ด์ธ CQL(Cassandra Query Language)์ ์ ๊ณตํฉ๋๋ค.
์ด๋ SQL๊ณผ ๋น์ทํ์ง๋ง join ๋ฐ subquery๋ฅผ ์ ๊ณตํ์ง ์๊ณ ์ธ๋ ํค๊ฐ ์๋ค๋ ํน์ง์ด ์์ต๋๋ค.// ํ ์ด๋ธ ์์ฑ CREATE TABLE users ( user_id uuid PRIMARY KEY, first_name text, last_name text, email text, password text, created_at timestamp ); // ๋ฐ์ดํฐ ์ฝ์ INSERT INTO users (user_id, first_name, last_name, email, password, created_at) VALUES (uuid(), 'John', 'Doe', 'john.doe@example.com', 'password123', toTimestamp(now())); // ๋ฐ์ดํฐ ์กฐํ SELECT * FROM users WHERE user_id = f3f9e3e3-301b-4c8a-ae0a-ccbae7b477a2; // ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ UPDATE users SET password = 'newpassword123' WHERE user_id = f3f9e3e3-301b-4c8a-ae0a-ccbae7b477a2; // ๋ฐ์ดํฐ ์ญ์ DELETE FROM users WHERE user_id = f3f9e3e3-301b-4c8a-ae0a-ccbae7b477a2;
Document Store#
Document Store๋ ํํ ์๊ณ ์๋ JSON ํ์์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์
๋๋ค.
Document Store์๋ ํ
์ด๋ธ์ ๋ํ๋ด๋ collection
๊ณผ ํ
์ด๋ธ ๋ด row๋ฅผ ๋ํ๋ด๋ document
๊ฐ ์์ต๋๋ค.
(๊ฐ document๊ฐ collection์ ์ ์ฅ๋๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.)
์ฅ์ #
collection ๋ด document๋ค๋ผ๋ฆฌ ๋์ผํ ๊ตฌ์กฐ์ด์ง ์์๋ ๋๊ธฐ ๋๋ฌธ์
์คํค๋ง๋ฅผ ์ ํ์ง ์๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ผ๋ฉฐ, ์คํค๋ง๊ฐ ๋ณ๊ฒฝ๋์ด๋ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์ ์ฅํ ์ ์์ต๋๋ค.๋ฐ์ดํฐ๊ฐ ์ง๊ด์ ์ด๊ณ , ๊ฐ๋ฐ ์ ๊ฐ์ฒด๋ก ๋ฐ๋ก ์ ์ฉํ ์๋ ์์ต๋๋ค.
ํ ์ด๋ธ ๊ฐ join ๋ํ ํ์ํ์ง ์์ต๋๋ค.
๋จ์ #
์ค๋ณต ๋ฐ์ดํฐ์ ๋ํ ๊ด๋ฆฌ๊ฐ ์ด๋ ต๋ค๋ ๋จ์ ์ด ์์ต๋๋ค.
๋ง์ฝ ํน์ ๊ฐ์ ๋ค๋ฅธ ๋ฌธ์๋ก ๋ณต์ฌํ ๋ค์ ๊ทธ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค๋ฉด,
๋ค๋ฅธ ๋ฌธ์ ๋ด์ฉ๋ ๋ณ๊ฒฝํ๊ธฐ ์ํด ๋ณต์ฌ๋ฅผ ํด์๋ ๋ฌธ์๋ฅผ ๊ธฐ์ตํด์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์์ต๋๋ค.
์ฌ์ฉ ์์#
์ํ ์นดํ๋ก๊ทธ
{ "product_id": 123, "name": "Macbook M2 Pro", "category": { "category_id": "345", "name": "laptop" } }
Event logging : ์ ์ ๋ก๊ทธ, ์ ํ ๊ตฌ๋งค ๋ด์ญ, ์ค๋ฅ ๋ก๊ทธ ๋ฑ
Top 10 Document Stores#
Document Store์์๋ ์ด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์๊น์?
์์์์ ๊ฐ์ด https://db-engines.com๋ฅผ ํตํด Top 10 Document Stores๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
MongoDB#
๋ญํน์์ ์๋์ ์ธ score๋ฅผ ๋ณด์ด๋ ๋งํผ Document Store๋ฅผ ๋ํํ๋ค๊ณ ๋ณผ ์ ์๋ MongoDB๋ BSON(Binary JSON) ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค.
Cassandra๊ฐ CQL์ ์ ๊ณตํ๋ ๊ฒ๊ณผ ์ ์ฌํ๊ฒ ์์ฒด ์ฟผ๋ฆฌ ์ธ์ด์ธ MQL(MongoDB Query Language)์ ์ ๊ณตํฉ๋๋ค.
// ๋ฐ์ดํฐ ์ฝ์ db.users.insertOne({ "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "password": "password123", "created_at": new Date() }) // ๋ฐ์ดํฐ ์กฐํ db.users.find({ "email": "john.doe@example.com" }) // ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ db.users.updateOne( {"email": "john.doe@example.com"}, {$set: {"password": "newpassword123"}} ) // ๋ฐ์ดํฐ ์ญ์ db.users.deleteOne({ "email": "john.doe@example.com" })
๋ํ sharding ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ์ฌ๋ฌ ์๋ฒ์ ๋ถ์ฐ ์ ์ฅ์ ํ ์๋ ์์ต๋๋ค.
Graph Store#
Graph Store๋ ๋ง ๊ทธ๋๋ก ๊ทธ๋ํ ๊ตฌ์กฐ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ฉฐ, node ๋ฐ edge ์ ๋ณด๋ฅผ ์ ์ฅํ๊ฒ ๋ฉ๋๋ค.
Graph Store์ ์ฃผ์ ํน์ง์ผ๋ก๋ ์ฟผ๋ฆฌ ํํ๊ฐ ๊ทธ๋ํ๋ฅผ traversing ํ๋ ์์ผ๋ก ์งํ๋๋ค๋ ์ ์ด ์์ต๋๋ค.
์๋ฅผ ๋ค์ด A๊ฐ ํ๋ก์ฐํ๊ณ ์๋ ๋ชจ๋ user ์ฐพ์ผ๋ ค๊ณ ํ ๋, user A์ ๋ํ node์์ ํ๋ก์ฐ์ ๊ด๋ จ๋ edge๋ฅผ ํตํด ๋ค๋ฅธ user node ์ ๋ณด๋ฅผ ์ป๋ ๋ฑ๊ณผ ๊ฐ์ด ๊ทธ๋ํ์ node์ edge๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด ์ํ๋ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๋ค.
์ฅ์ #
์ต์ข ๊ตฌ์กฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ํ ํ์ ์์ด node, edge ๋ฐ ํด๋น ์์ฑ์ ๊ธฐ์กด ๊ทธ๋ํ์ ์ถ๊ฐํ๊ฑฐ๋ ์ญ์ ํ ์ ์์ต๋๋ค.
์ด๋ฏธ ๋ฐ์ดํฐ๊ฐ ์๋ก ์ฐ๊ฒฐ๋์ด ์๊ธฐ ๋๋ฌธ์ join์ ์ํํ ํ์ ์์ด ํน์ node์์๋ถํฐ ๋ค๋ฅธ node๊น์ง edge๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด ์ํ๋ ๊ฐ์ ์ป์ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ํ์์ด ์ง๊ด์ ์ด๊ณ ์๊ฐํํ๊ธฐ ์ฝ์ต๋๋ค.
๋จ์ #
๊ทธ๋ํ ํ์์ผ๋ก ํํ ๊ฐ๋ฅํ ๋ฐ์ดํฐ์๋ง ์ ํฉํฉ๋๋ค.
์๋ก์ด ์ฟผ๋ฆฌ ์ธ์ด(Cypher, SPARQL ๋ฑ)๋ฅผ ์ด์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฌ๋์ปค๋ธ๊ฐ ์์ต๋๋ค.
์ฌ์ฉ ์์#
์์ ๋คํธ์ํฌ ๋ฐ์ดํฐ (์ฌ๋๋ค ๊ฐ ํ๋ก์ฐ ์ ๋ณด, ๊ฒ์๋ฌผ ๋ฐ ์ข์์ ์ ๋ณด ๋ฑ)
์ ์ผ๋ณ ๋ฐ์ดํฐ (์ฌ๋๋ค ๊ฐ ์ ์ด ์ ๋ณด, ๊ฐ์ผ ์ฌ๋ถ ๋ฑ)
๊ฒฝ๋ก ์๋ด ์๋น์ค (์ฅ์ ๊ฐ ๊ฑฐ๋ฆฌ ์ ๋ณด๋ก ์ต์ ๊ฒฝ๋ก ์ ๊ณต)
์ถ์ฒ์์คํ (์ ์ฌํ ์ฌ์ฉ์๊ฐ ์์ฒญํ ๋ค๋ฅธ ์ํ๋ฅผ ๊ทธ๋ํ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์)
Top 10 Graph Stores#
๋ง์ง๋ง์ผ๋ก Graph Store์์๋ ์ด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์๊น์?
Graph Store ๋ํ https://db-engines.com๋ฅผ ํตํด Top 10 Graph Stores๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Neo4j#
๋ํ์ ์ธ Graph Store์ธ Neo4j๋ ์๋์ ๊ฐ์ ์ํคํ ์ณ๋ฅผ ์ง๋๊ณ ์์ต๋๋ค.
์์ฒด์ ์ผ๋ก Neo4j graph ํ๋ซํผ์ ์ ๊ณตํ๊ณ ์์ด์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ์ ์ฉ์ดํฉ๋๋ค.
๊ทธ๋ํ์ ๊ด๋ จ๋ ๋ค์ํ ์๊ณ ๋ฆฌ์ฆ ๊ธฐ๋ฅ ๋ํ ์ ๊ณตํฉ๋๋ค.
path finding
centrality
community detection
similarity
link prediction
node embeddings
node classification
โฆ
๋ฐ์ดํฐ ์ ๊ทผ ์์๋ Cypher ์ฟผ๋ฆฌ ์ธ์ด๋ฅผ ํตํด ์ ๊ทผํ ์ ์์ต๋๋ค.
// node ์์ฑ CREATE (n:Person { name: 'John Doe', age: 30 }) // node ๊ฒ์ MATCH (n:Person { name: 'John Doe' }) RETURN n // node ๊ฐ edge ์์ฑ MATCH (p1:Person { name: 'John Doe' }), (p2:Person { name: 'Jane Smith' }) CREATE (p1)-[:FRIENDS_WITH]->(p2) // node ๋ฐ edge ๊ฒ์ MATCH (p1:Person)-[:FRIENDS_WITH]->(p2:Person) WHERE p1.name = 'John Doe' RETURN p1, p2 // edge ์์ MATCH (p1:Person)-[r:FRIENDS_WITH]->(p2:Person) WHERE p1.name = 'John Doe' AND p2.name = 'Jane Smith' SET r.since = '2022-01-01' // edge ์ ๊ฑฐ MATCH (p1:Person)-[r:FRIENDS_WITH]->(p2:Person) WHERE p1.name = 'John Doe' AND p2.name = 'Jane Smith' DELETE r