본문 바로가기

볼봇의 코딩 생활/웹 세계

[클라우드응용SW개발] 관계형 DB부터 Cosmos DB까지

1강. 관계형 데이터베이스의 핵심 개념과 SQL 쿼리

테이블 — 데이터가 저장되는 공간

관계형 데이터베이스에서 모든 데이터는 테이블(Table)에 저장된다. 테이블은 행(Row)과 열(Column)로 구성되며, 각 행은 하나의 데이터 레코드를 나타낸다.

각 열에는 데이터 타입을 지정해야 한다. 예를 들어 CustomerID 같은 숫자 필드는 INT, 이름처럼 문자열 필드는 VARCHAR(50), 전화번호처럼 대시(-)를 포함하는 필드도 VARCHAR(25)로 지정한다. 숫자처럼 보여도 실제 용도에 따라 텍스트 타입을 써야 하는 경우가 있다는 점을 기억하자.

정규화(Normalization) — 데이터 중복을 줄이는 핵심 작업

고객이 여러 번 주문을 하면, 주문 테이블에 매번 고객 이름과 전화번호를 반복 저장해야 할까? 이렇게 하면 두 가지 문제가 생긴다.

첫째, 저장 공간이 낭비된다. 둘째, 고객이 전화번호를 변경하면 주문 테이블에는 옛날 번호가 남아 있어 데이터 불일치가 발생한다. 이를 해결하기 위해 고객 고유 ID만 주문 테이블에 저장하고, 실제 고객 정보는 고객 테이블에서 참조하는 방식을 사용한다. 이것이 바로 정규화다.

💡 기본 키(Primary Key)와 외래 키(Foreign Key)
고객 테이블의 CustomerID는 기본 키, 주문 테이블에서 이를 참조하는 CustomerID는 외래 키다. 이 둘을 연결하는 것을 관계(Relationship)라 부르며, 이런 구조의 데이터베이스를 관계형 데이터베이스(RDBMS)라 한다. Oracle, MySQL, SQL Server 모두 RDBMS에 해당한다.

인덱스(Index) — 검색 속도를 높이는 색인

도서관에서 책을 찾을 때 처음부터 끝까지 하나씩 훑어보는 사람은 없다. 검색 컴퓨터를 이용해 위치를 먼저 확인하고 바로 찾아간다. 데이터베이스의 인덱스도 마찬가지다. 고객 데이터가 수백만 건이 될 때, 인덱스 없이 전체를 검색하면 엄청난 시간이 걸린다. 인덱스를 만들어 두면 필요한 데이터의 위치를 빠르게 찾을 수 있다.

뷰(View) — 데이터 접근 권한을 제어하는 가상 테이블

고객 테이블에는 이름, 전화번호, 주소 등 민감한 정보가 포함되어 있다. 모든 사용자에게 전체 데이터를 보여줄 수는 없다. 뷰를 사용하면 역할에 따라 볼 수 있는 컬럼을 다르게 설정할 수 있다. 고객센터 직원에게는 대부분의 정보를, 배송 담당자에게는 주소와 전화번호만 보여주는 식이다.

SQL문의 유형

유형이름용도명령어

DML 데이터 조작 언어 데이터를 조회하고 조작 SELECT, INSERT, UPDATE, DELETE
DDL 데이터 정의 언어 테이블 등 DB 객체 정의 CREATE, ALTER, DROP, RENAME
DCL 데이터 제어 언어 보안 및 권한 관리 GRANT, REVOKE, DENY

DML에서 가장 자주 쓰이는 패턴은 CRUD로, Create(INSERT), Read(SELECT), Update(UPDATE), Delete(DELETE) 네 가지 작업을 의미한다. 모든 프로그램은 결국 이 네 가지 작업의 조합이다.

SELECT 쿼리 구조

SELECT 컬럼목록
FROM 테이블명
WHERE 조건
GROUP BY 그룹기준
HAVING 그룹조건
ORDER BY 정렬기준

SELECT로 가져올 컬럼을 지정하고, FROM으로 데이터 출처를 정하고, WHERE로 조건을 걸고, GROUP BY로 그룹화하고, ORDER BY로 정렬한다. 이 기본 구조만 잘 이해해도 대부분의 데이터 조회가 가능하다.


2강. MySQL 실습과 상용 클라우드 데이터베이스

MySQL Tutorial 사이트로 SQL 쿼리 학습하기

SQL 쿼리는 듣기만 해서는 익숙해지지 않는다. 직접 데이터를 넣고 쿼리를 작성해봐야 실력이 는다. mysqltutorial.org 사이트에서 제공하는 classicmodels 샘플 데이터베이스를 활용하면 체계적으로 연습할 수 있다.

샘플 데이터베이스를 다운로드하고, MySQL Workbench에서 SQL 스크립트를 실행하면 고객, 주문, 제품 등 다양한 테이블이 자동 생성된다. 이후 사이트의 튜토리얼을 따라가며 SELECT FROM, WHERE, ORDER BY 등을 하나씩 실습하면 된다.

-- 직원의 성(lastName)만 조회
SELECT lastName FROM employees;

-- 직원의 성, 이름, 직책 조회
SELECT lastName, firstName, jobTitle FROM employees;

-- 모든 컬럼 조회
SELECT * FROM employees;

Azure에서 제공하는 상용 데이터베이스 유형

Azure는 데이터베이스를 IaaS와 PaaS 두 가지 방식으로 제공한다.

서비스유형특징

Azure VM의 SQL Server IaaS 온프레미스와 호환성 높음. OS 업그레이드, 백업 등을 직접 관리해야 함. 서버+라이선스 비용 결제
Azure SQL Managed Instance PaaS (IaaS 호환) 기존 SQL Server와 99.99% 호환. 백업, 패치 등은 클라우드에서 관리
Azure SQL Database PaaS 가장 완전한 PaaS. 관리 부담 최소화. 재시작 없이 Scale Up/Down 가능
💡 Scale Up vs Scale Out
Scale Up은 하나의 시스템 용량을 키우는 것이고, Scale Out은 같은 사양의 시스템 수를 늘리는 것이다. 반대로 줄이는 것은 각각 Scale Down, Scale In이라 한다. 클라우드에서는 재시작 없이 이 작업이 가능하다는 것이 큰 장점이다.

3강. Python으로 MySQL 연동하기

MySQL Connector 라이브러리

Python에서 MySQL에 접속하려면 mysql-connector-python 패키지를 사용한다. Oracle이 공식 지원하는 라이브러리로, 순수 Python으로 작성되어 호환성이 좋다. 다만 C로 작성된 라이브러리에 비해 상대적으로 속도가 느리므로, 대규모 트래픽 서비스에는 다른 라이브러리를 고려해야 한다.

# 패키지 설치
pip install mysql-connector-python

DB 연결 및 데이터 입력 코드

import mysql.connector

# 데이터베이스 연결 함수
def connect_to_db():
    return mysql.connector.connect(
        host='helloai-mysql-001.mysql.database.azure.com',
        user='winkey',
        password='Password8282',
        database='notes_db'
    )

conn = connect_to_db()
cursor = conn.cursor()

# 사용자 입력 받기
title = input('Enter the title of your note: ')
note = input('Enter the content of your note: ')

# INSERT 쿼리 실행
insert_query = 'INSERT INTO notes (title, note) VALUES (%s, %s)'
cursor.execute(insert_query, (title, note))

conn.commit()
print(f"Note '{title}' added successfully!")

cursor.close()
conn.close()
⚠️ 방화벽 설정 필수!
Azure MySQL에 외부에서 접속하려면, MySQL 서비스의 네트워킹 설정에서 접속할 IP 주소를 방화벽 규칙에 등록해야 한다. 등록하지 않으면 연결 시 타임아웃 에러가 발생한다.

MySQL Workbench에서 DDL 쿼리로 테이블을 먼저 생성한 후, Python 코드로 데이터를 입력하고 확인하는 흐름이다.

-- notes 테이블 생성 (DDL)
CREATE TABLE notes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    note TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

4강. 클라우드 기반의 NoSQL과 JSON

반정형(Semi-structured) 데이터란?

관계형 데이터베이스의 테이블은 모든 행이 동일한 구조(스키마)를 갖는다. 반면 반정형 데이터는 키-값 쌍으로 구성되지만, 각 데이터마다 항목이 다를 수 있다. 예를 들어 고객 1에게는 "이름, 전화번호, 주소"가 있고, 고객 2에게는 "직함, 이름, 전화번호"가 있을 수 있다.

이처럼 관계(Relationship)를 설정할 수 없기 때문에 비관계형(Non-relational) 데이터라고도 부른다. IoT, 게임, 웹, 모바일 분야에서 특히 많이 사용된다.

JSON (JavaScript Object Notation)

반정형 데이터의 대표 포맷이 JSON이다. 서버-클라이언트 간 데이터 통신에서 사실상 업계 표준으로 자리잡았다.

{
    "name": "John",
    "age": 35,
    "city": "San Francisco",
    "hobbies": ["reading", "swimming"]
}

JSON의 장점은 가볍고, 사람이 읽기 쉬우며, 거의 모든 프로그래밍 언어에서 파싱이 가능하다는 것이다. XML에 비해 데이터 크기가 작아 효율적이다. 단점으로는 매우 복잡한 데이터 타입 표현에 한계가 있고, 주석(Comment)을 지원하지 않는다는 점이 있다.

기타 데이터 포맷

포맷특징용도

Apache Avro 스키마 기반 직렬화 시스템. 효율적 저장 및 빠른 직렬화/역직렬화 빅데이터 환경 데이터 교환
ORC 컬럼(열) 기반 저장 방식. 특정 컬럼만 읽을 때 효율적 Hadoop/Hive 환경
Parquet 역시 컬럼 기반 저장. ORC와 유사 빅데이터 분석

Azure에서 비정형 데이터를 파일 형태로 저장할 때는 Storage Account를 사용한다. Blob, Table, File, Queue, Disk 등 용도별 다양한 저장 공간을 제공한다.


5강. Cosmos DB의 이해와 활용

Cosmos DB는 '데이터베이스'가 아니다?

Azure Cosmos DB라는 이름에 'DB'가 붙어 있지만, 정확히 말하면 데이터베이스 관리 시스템(DBMS)에 더 가깝다. Cosmos DB는 여러 종류의 데이터베이스를 지원하는 관리 플랫폼이다. 처리 속도 보장, 글로벌 데이터 복제 등의 기능을 Cosmos DB 차원에서 관리해준다.

Cosmos DB가 지원하는 API

API데이터 모델주요 특징

NoSQL API JSON 문서 SQL과 유사한 쿼리 사용 가능. 가장 많이 사용됨
MongoDB API JSON/BSON 문서 기존 MongoDB 앱과 호환. 바이너리 레벨 처리로 빠름
Cassandra API 와이드 컬럼 대규모 IoT, 고성능 시스템에 적합
Gremlin API 그래프 소셜 네트워크, 복잡한 관계 분석
PostgreSQL API 관계형 Cosmos DB에서 유일하게 지원하는 관계형 DB

RU(Request Unit) — Cosmos DB의 비용 단위

Cosmos DB의 모든 작업 비용은 RU(Request Unit)로 측정된다. 읽기 작업은 RU가 저렴하고, 쓰기 작업은 약 3배 정도 비싸다. Serverless 모드에서는 사용한 RU만큼만 과금된다.

⚠️ Cosmos DB 비용 주의!
Cosmos DB는 기능이 강력하지만 비용이 높다. 쓰기가 많은 서비스에는 비용 폭탄이 될 수 있다. 로그인 인증처럼 쓰기는 적고 읽기가 많은 서비스에 적합하다. 꼭 필요한 곳에 제한적으로 사용하는 것이 좋다.

6강. Cosmos DB 아키텍처 구성 — Python 코드로 실습

사전 준비

Cosmos DB를 Python에서 사용하려면 azure-cosmos 패키지가 필요하다.

pip install azure-cosmos

Cosmos DB 연결 및 데이터 CRUD

from azure.cosmos import exceptions, CosmosClient, PartitionKey

# 연결 정보
url = 'https://helloai-cosmosdb-01.documents.azure.com:443/'
key = '여기에_Primary_Key_입력'
database_name = 'MyDatabase'
container_name = 'MyContainer'

# 클라이언트 생성
client = CosmosClient(url, credential=key)

# 데이터베이스 생성 (없으면 새로 만듦)
database = client.create_database_if_not_exists(id=database_name)

# 컨테이너 생성 (없으면 새로 만듦)
container = database.create_container_if_not_exists(
    id=container_name,
    partition_key=PartitionKey(path='/category')
)

# 데이터 입력 (Upsert: 없으면 추가, 있으면 수정)
def insert_data():
    item = {
        "id": "1",
        "category": "Technology",
        "name": "Azure Cosmos DB",
        "description": "A globally distributed, multi-model database service"
    }
    container.upsert_item(item)
    print(f"Item with id {item['id']} inserted or updated")

# 데이터 조회
def query_data():
    query = "SELECT * FROM c WHERE c.category = 'Technology'"
    items = container.query_items(
        query=query,
        enable_cross_partition_query=True
    )
    for item in items:
        print(f"ID: {item['id']}, Name: {item['name']}, Desc: {item['description']}")

insert_data()
query_data()

위 코드에서 핵심 포인트를 정리하면 다음과 같다. create_database_if_not_exists와 create_container_if_not_exists를 사용하면 이미 존재하는 경우 기존 것을 그대로 사용하고, 없을 때만 새로 생성한다. upsert_item은 같은 ID가 있으면 업데이트, 없으면 새로 추가하는 편리한 메서드다. 쿼리는 SQL과 유사한 문법을 사용할 수 있어 학습 비용이 낮다.

💡 Cosmos DB에 접근하려면?
Azure Portal → Cosmos DB → 설정 → 키 메뉴에서 URI(엔드포인트) Primary Key를 확인할 수 있다. Read/Write Key는 읽기+쓰기 모두 가능하고, Read Only Key는 읽기만 가능하다. 키가 노출되면 즉시 재생성(회전)하는 것이 안전하다.

전체 시리즈 요약

강의핵심 내용

1강 관계형 DB의 테이블, 정규화, 인덱스, 뷰 개념과 SQL 유형(DML/DDL/DCL)
2강 MySQL 샘플 DB로 SQL 쿼리 실습 + Azure 상용 DB(IaaS vs PaaS) 비교
3강 Python + MySQL Connector로 DB 연동. 방화벽 설정, DDL/INSERT 실습
4강 반정형 데이터와 JSON 포맷 이해. Avro, ORC, Parquet 등 빅데이터 포맷 소개
5강 Cosmos DB 개념(DB 관리 시스템), 5가지 API, RU 비용 구조
6강 Python + azure-cosmos로 Cosmos DB CRUD 실습

이 강의 시리즈를 통해 클라우드 환경에서 관계형 DB(MySQL, SQL Server)와 비관계형 DB(Cosmos DB)를 모두 다루는 기초를 쌓을 수 있었다. 핵심은 SQL 쿼리는 반드시 직접 작성하며 익혀야 한다는 것과, 클라우드 DB를 선택할 때 용도와 비용을 함께 고려해야 한다는 점이다.