들어가기 전에
내 언어의 한계는 내 세계의 한계를 의미한다.
- 루트비히 비트겐슈타인, 논리-철학 논고(1922)
[개념 사전]
단어 | 의미 |
다중 저장소 지속성 (polyglot persistence) |
관계형 데이터베이스가 폭넓은 다양함을 가진 비관계형 데이터스토어와 함께 사용될 것이라는 개념 |
임피던스 불일치 (impedance mismatch) |
객체지향 프로그래밍과 관계형 데이터베이스 모델 객체의 패러다임이 상충되는 것 |
문서 참조 (document reference) |
문서 모델에서 의존 관계를 표현할 때 참조하는 고유한 식별자 |
슈레딩(shredding) 관계형 기법 |
문서와 비슷한 구조를 여러 테이블로 나누는 것 |
쓰기 스키마 (schema-on-write) |
관계형 데이터베이스의 전통적인 접근 방식으로 스키마는 명시적이고 데이터 베이스는 쓰여진 모든 데이터가 스키마를 따르고 있음을 보장한다. |
읽기 쓰키마 (schema-on-read) |
데이터 구조는 암묵적이고 데이터를 읽을 때만 해석된다. |
맵 리듀스(MapReduce) | 많은 컴퓨터에서 대량의 데이터를 처리하기 위한 프로그래밍 모델 |
02장. 데이터 모델과 질의 언어
[핵심 내용]
이번 장에서는 애플리케이션의 요구사항에 따라 적합한 모델을 찾을 수 있도록 다양한 종류의 데이터 모델을 배운다. 세 가지 모델(문서, 관계형, 그래프)은 각기 목적에 맞게 사용되어야 기대하는 결과를 얻을 수 있고, 개발자는 하나의 솔루션으로 모든 것을 처리하려고 하기보다는 데이터 모델을 이해하고 목적에 맞는 시스템을 사용해야 한다는 것을 알 수 있다.
새롭게 알게된 점(New)
[1] 관계형 모델의 탄생
- 1970년대에 많이 사용한 데이터베이스인 IMS(Information Management System)의 데이터 모델은 계층 모델이다.
- 계층 모델은 JSON 구조처럼 레코드 내에 중첩된 레코드 트리로 표현한다.
- 계층 모델의 한계를 위해 고안된 것들 중에 관계형 모델과 네트워크 모델이 양대산맥이었다.
다대다 관계를 표현하기에는 트리 구조(계층 모델)이 적절하지 않아 관계형 모델이 고안되었는데, 최근에 관계형 모델에도 적합하지 않은 애플리케이션이 있다는 사실이 발견되어 비관계형 데이터저장소인 NoSQL이 새롭게 등장하였다.
🔉 NoSQL의 두 가지 주요 갈래
1. 문서 데이터베이스 : 데이터가 문서 자체에 포함, 하나의 문서와 다른 문서 간 관계가 거의 없는 사용 사례 대상
2. 그래프 데이터베이스 : 모든 것이 잠재적으로 관련 있다는 사용 사례 대상
[2] MySQL의 ALTER TABLE 성능 저하
MySQL의 ALTER TABLE은 전체 테이블을 복사하기 때문에 성능 저하의 위험이 있다.
🤔 MySQL에서 테이블이 아주 큰 경우에 ALTER TABLE은 성능 문제를 일으킬 수 있다?
MySQL에서 대부분의 변경 작업은 원하는 구조를 갖춘 빈 테이블을 만들고, 이 테이블에 기존 테이블의 데이터를 삽입한 뒤 기존 테이블을 삭제하는 식으로 수행한다. 테이블이 크거나 인덱스가 많을 때 그리고 메모리가 부족한 경우라면 이런 작업은 특히나 오래 걸릴 수 있다. 심지어 ALTER TABLE 연산에 수시간, 수일을 보낸 사람들도 많다.
<MySQL 성능 최적화 도서>, p167
실제로 스터디 시간에 해당 내용에 대해 이야기했을 때 보통 이런 경우 마이그레이션을 하게 되며, 실제 2억 개 정도의 데이터를 가진 테이블에서 ALTER TABLE 대신 원하는 데이터 구조로 테이블을 새로 구성하고 데이터를 옮기는 것을 선택하셨다고 들었다.
[3] 지역성 관리
웹 페이지 상에 문서를 보여주는 동작처럼 애플리케이션이 자주 전체 문서에 접근해야 할 때 저장소 지역성(storage locality)을 활용하면 성능 이점이 있다. 지역성의 이점은 한 번에 해당 문서의 많은 부분을 필요로 하는 경우에만 적용된다.
e.g. 구글 Spanner 데이터베이스의 지역성 관리 기법
부모 테이블(Users) 내에 자식 테이블(Orders)의 데이터를 중첩 저장한다.
Users
├── user_id: 1 (헤일리)
│ ├── Orders (order_id: 101, item: 스마트폰)
│ ├── Orders (order_id: 102, item: 키보드)
│
├── user_id: 2 (더그)
│ ├── Orders (order_id: 103, item: 모니터)
어려웠거나 이해하지 못한 부분(Difficulty)
맵 리듀스 질의
맵 리듀스는 선언형 질의 언어도 완전한 명령형 질의 API도 아닌 그 중간 정도에 있다.
질의 로직은 처리 프레임워크가 반복적으로 호출하는 조각 코드로 표현한다. 여러 함수형 프로그래밍 언어에 있는 map(collect)과 reduce(fold, inject) 함수를 기반으로 한다.
예를 들어, 한 달에 얼마나 자주 상어를 발견하는지 보고서를 작성하려고 할 때의 질의를 비교해 보자.
[1] PostgreSQL
SELECT date_trunc('month', observation_timestamp) AS observation_month,
sum(num_animals) AS total_animals
FROM observations
WHERE family = 'Sharks'
GROUP BY observation_month;
[2] MongoDB의 맵리듀스 기능
db.observations.mapReduce(
function map() {
var year = this.observationTimestamp.getFullYear();
var month = this.observationTimestamp.getMonth() + 1;
emit(year + "-" + month, this.numAnimals);
},
function reduce(key, values) {
return Array.sum(values);
},
{
query: { family: "Sharks" },
out: "monthlySharkReport"
}
);
🔉 MongoDB의 집계 파이프라인(aggregation pipeline)이 생겨난 이유
맵리듀스의 사용성 문제는 연계된 자바스크립트 함수 두 개를 신중하게 작성해야 한다는 점인데 이는 종종 하나의 질의를 작성하는 것보다 어렵다. 더욱이 선언형 질의 언어는 질의 최적화기가 질의 성능을 높일 수 있는 기회를 제공한다. 이런 이유로 MongoDB는 집계 파이프라인이라 부르는 선언형 질의 언어 지원을 추가했다.
db.observations.aggregate([
{ $match: { family: "Sharks" } },
{ $group: {
_id: {
year: { $year: "$observationTimestamp" },
month: { $month: "$observationTimestamp" }
},
totalAnimals: { $sum: "$numAnimals" }
} }
]);
추가 내용(Amendment)
[1] 선언형 질의 언어 vs 명령형 질의 API
종류 | 의미 | 예 |
선언형 질의 언어 (Declarative Query Language) |
사용자가 무엇을 할지 기술, 어떻게 할지는 시스템이 알아서 최적화하여 실행하는 방식 | SQL |
명령형 질의 API(Imperative Query API) | 사용자가 무엇을 할지, 어떻게 처리할지 직접 명령하는 방식 | 전통적인 프로그래밍 언어 (Java, Python 등) |
[2] 맵 리듀스가 “그 중간”이라 설명되는 이유
사용자는 맵과 리듀스 연산 수행 지시를 함과 동시에 무엇을 할지 내부 로직을 일부 구현해야 한다. 그리고 시스템이 내부적으로 분산 실행을 최적화한다.
public static class Map extends Mapper<LongWritable,Text,Text,IntWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException,InterruptedException {
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
value.set(tokenizer.nextToken());
context.write(value, new IntWritable(1));
}
}
참고 자료
'노트' 카테고리의 다른 글
[DDIA] 01장. 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션 (0) | 2025.03.16 |
---|---|
모니터링 툴 씬의 맛없없 조합: Spring Boot Actuator X Prometheus X Grafana (0) | 2025.03.02 |
Github Actions (CI) (0) | 2023.02.23 |
Testcontainers (0) | 2023.02.20 |