Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions 윤성하/[lecture19] mvcc (1부)/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Lock은 처리량이 줄어들어 문제 -> MVCC 등장

MVCC는 write-write를 제외하면 동시에 처리 가능

write lock을 사용하지 않고도 MVCC를 구현 가능하지만, 오늘날 대부분의 RDB는 write lock을 사용하여 구현한다

- MVCC는 commit된 데이터만 읽는다 <- dirty read발생 x
- Recoverability를 위해 commit 할 때 write lock 반환 <- Strict 2PL과 유사
- 데이터 변화 이력을 관리

## Isolation Level에 따른 read 시점
- read uncommitted: MVCC 자체가 commit 된 데이터를 읽도록 하므로 보통 해당 레벨은 MVCC 자체가 적용되지 않는다
- read committed: read하는 시간을 기준으로 commit 되어 있는 데이터 읽기 가능
- repeatable read: tx 시작 시간 기준(db마다 다를 수 있음)으로 commit 되어 있는 데이터만 읽기 가능
- serializable: repeatable read와 동일


Consistent read: 데이터를 읽을 때 특정 시점을 기준으로 commit 된 데이터 읽기
> [The query sees the changes made by transactions that committed before that point in time, and no changes made by later or uncommitted transactions.](https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html)

MVCC가 적용되었더라도 read committed level에서 LOST UPDATE 발생 가능
-> repeatable read로 바꾸면?
1. 하나의 tx만 repeatable read로 변경: 여전히 다른 schedule에서 LOST UPDATE 발생 가능
2. 모든 tx repeatable read로 변경: first committer win의 원리에 따라서 나중에 write하는 tx는 rollback됨 (단, 이건 postgresql만 해당. mysql은 여전히 LOST UPDATE 존재)
39 changes: 39 additions & 0 deletions 윤성하/[lecture20] mvcc (2부)/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Mysql의 locking read는 가장 최근의 commit된 데이터를 읽는다. (repeatable read level이여도 동일하게 적용)

## Locking Read의 종류

SELECT ... FOR UPDATE;
> 이건 write lock

SELECT ... FOR SHARE;
> 이건 read lock

## 그럼에도 해결되지 않은 문제

MVCC + repeatable read를 사용하였는데도 발생하는 문제가 남아있다.

WRITE SKEW! <- 이건 write lock을 적용하면 해결 가능하다
다만, mysql과 postgresql의 결과는 다르다.

mysql: 두 tx 모두 정상적으로 commit
postgresql: 먼저 commit된 tx만 commit. 다른건 rollback (write lock 뿐 아니라 read lock이여도 repeatable read level에서는 먼저 update tx가 commit하면 나중 tx는 rollback 된다)


## Serializable은 어떻게 동작할까?

MYSQL
- repeatable read와 유사
- tx의 모든 평범한 select 문은 암묵적으로 select ... for share 처럼 동작한다

> [!NOTE]
> 왜 for share 일까?
>
> - for update는 일종의 write lock이기 때문에 성능상 좋지 않음
>
> 하지만 shared lock은 exclusive lock에 비해 deadlock 발생 가능성이 높다

POSTGRESQL
- SSL(Serializable Snapshot Isolation)[^1]로 구현
- first-committer-winner

[^1]: MVCC로 동작하면서도 모든 이상현상을 방지하는 기법이다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Insertion anomalies
- 중복된 데이터가 많다
- 저장 공간 낭비
- 실수로 인한 데이터 불일치 가능성 존재 (오타, ...)
- null값이 많다. (null은 적게 쓰는 것이 좋다.)
- SQL에서 NULL과 비교 연산을 하게 되면 그 결과는 UNKNOWN이다(TRUE, FALSE 아님!)
- three-valued logic: 비교/논리 연산의 결과로 TRUE, FALSE, UNKNOWN을 가진다
- WHERE 절은 condition의 결과가 TRUE인 tuple만 선택된다.
- v NOT IN (v1, v2, v3)를 살펴보자
- 3 NOT IN (1, 2, NULL) -> UNKNOWN!!!!!!!!
- 서브쿼리를 작성 할 때 주의해야한다 (WHERE D.id NOT IN (some subquery...))
- 강제적인 불필요한 데이터 입력
- 두 개 이상의 관심사가 하나의 테이블에 존재한다

해결: 관심사별로 테이블을 분리하자

Deletion anomalies
- 특정 데이터를 삭제할 때 관련된 다른 유용한 정보까지 함께 삭제

Update anomalies
- 하나의 값을 수정해야 할 때, 동일한 데이터가 여러 레코드에 존재하면 모든 곳에서 동일하게 업데이트 필요

Spurious Tuples
- 조인 연산을 수행할 때 잘못된 설계로 인해 발생하는, 의미가 없는 불필요한 튜플들

많은 null
이게 왜 문제?
- null값이 있는 column으로 join 하는 경우 상황에 따라 예상과 다른 결과 발생
- null 값이 있는 column에 aggremate function을 사용했을 때 주의 필요
- 불필요한 storage 낭비

그럼 어떻게 DB를 설계해야 하나?
- 의미적으로 관련있는 속성들끼리 테이블을 구성
- 중복 데이터를 최대한 허용하지 않도록 설계
- join 수행 시 가짜 데이터가 생기지 않도록 설계 (PK, FK!)
- 되도록이면 null 값을 줄일 수 있는 방향으로 설계
- 다만, 성능 향상을 위해 일부러 테이블을 나누지 않을 수 도 있다 (비정규화, 반정규화)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Functional Dependency

한 테이블에 있는 두 개의 attribute set 사이의 제약

X값에 따라 Y값이 유일하게 결정될 때
> X가 Y를 함수적으로 결정한다
> Y가 X에 함수적으로 의존한다
>
> 표기: X(left hand side) → Y(right hand side)

이러한 관계를 Functional Dependency라고 부른다.

> [!NOTE]
>
> X → Y 라고 해서 Y → X는 아니다
> {} → Y의 의미는 언제나 항상 Y라는 값만 나온다

### Functional Dependency를 파악할 때 주의할 점

테이블의 스키마를 보고 의미적으로 파악해야 한다.
→ 테이블의 특정 순간의 특정 상태(state)만 보고 파악하면 안된다.

ex) 사람의 이름으로 생일이 결정되는가?
사람의 이름은 중복될 수 있기 때문에 사람의 이름으로는 unique한 값이 결정될 수 없다

구축하려는 DB의 attributes가 관계적으로 어떤 의미를 지니는지에 따라 FD가 달라진다.
(같은 테이블이더라도 정책에 따라 FD가 될 수도 안될 수도)

### FD의 예

{stu_id} → {stu_name, birth_date, address}

{class_id} → {class_name, year, semester, credit}

{stu_id, class_id} → {grade}

{bank_name, bank_account} → {balance, open_date}

{user_id, location_id, visit_date} → {comment, picture_url}

### FD의 종류

- Trivial Functional Dependency
- X → Y 일 때, Y가 X의 subset인 경우
- {a, b, c} → { c }: trivial FD
- Non-trivial functional Dependency
- X → Y 일 때, Y가 X의 subset이 아닌 경우
- {a, b, c} → {b, c, d}: non-trivial FD
- 공통된 attribute가 단 하나도 없는 경우는 completely non-trivial FD라고 부른다
- Partial Functional Dependency
- X → Y 일 때 X의 진부분집합이 Y를 결정지을 수 있는 경우
- {empl_id, empl_name} → {birth_date}, {empl_id} → {birth_date}
- Full Functional Dependency
- X → Y 일 때 X의 진부분집합이 Y를 결정지을 수 없는 경우
35 changes: 35 additions & 0 deletions 윤성하/[lecture23] db 정규화 (1NF, 2NF)/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# DB 정규화

데이터 중복과 insertion, update, deletion anomaly를 최소화하기 위해 일련의 normal form(NF)에 따라 relational DB를 구성하는 과정

### Normal Form

정규화 되기 위해 준수해야 하는 몇 가지의 rule들

- 처음부터 순차적으로 진행
- 앞 단계를 만족해야 다음 단계로 진행 가능
- BCNF 단계까지는 FD와 key만으로 정의된다
- 일반적으로 3NF 또는 BCNF 까지만 정규화 진행

| 정규형 | 설명 |
| ------- | ----------------------------------------------------------------- |
| **1NF** | 모든 테이블은 원자값(나눌 수 없는 값)만을 포함해야 한다 |
| **2NF** | 모든 non-prime attribute는 모든 key에 fully functionally dependent해야 한다 |


> [!IMPORTANT]
>
> ### key가 composite key가 아니라면 2NF는 자동적으로 만족한다?
>
> 2NF는 모든 non-prime attribute는 어떤 key에도 partially dependent 하면 안된다
> → composite key가 아니라면 partially dependent 할 수 없으므로 일반적으로는 맞다.
>
> 하지만 앞에서 {} → Y인 FD가 있다고 배웠었다.
> 공집합도 key의 부분집합이므로 이러한 경우 2NF를 위반한다.

***
super key: table에서 tuple들을 unique하게 식별할 수 있는 attribute set
(candidate) key: 어느 한 attribute라도 제거하면 unique하게 튜플들을 식별할 수 없는 super key
primary key: table에서 튜플들을 unique하게 식별하기 위해 선택한 키
prime attribute: 임의의 key에 속하는 attribute
non-prime attribute: 어떠한 key에도 속하지 않는 attribute
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Transitive FD

X → Y 이고 Y → Z 가 성립한다면 X → Z 는 transitive FD이다
- Y와 Z 모두 어떤 key에 대해서도 부분집합이 아니여야 한다


| 정규형 | 설명 |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **3NF** | - 기본 키에 의존하지 않는 열을 제거<br>- non-prime attribute와 non-prime attribute 사이에는 FD가 있으면 안된다<br>- 모든 non-prime attribute는 어떤 key에도 transitively dependent하면 안된다 |
| **BCNF** | - 모든 결정자는 후보 키여야 한다<br>- 모든 유효한 non-trivial FD[^1] X → Y는 X가 super key여야 한다 |


[^1]: Y가 X의 부분 집합이 아닌 FD