diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture19] mvcc (1\353\266\200)/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture19] mvcc (1\353\266\200)/README.md"
new file mode 100644
index 0000000..6a73fbe
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture19] mvcc (1\353\266\200)/README.md"
@@ -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 존재)
\ No newline at end of file
diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture20] mvcc (2\353\266\200)/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture20] mvcc (2\353\266\200)/README.md"
new file mode 100644
index 0000000..2cc8754
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture20] mvcc (2\353\266\200)/README.md"
@@ -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로 동작하면서도 모든 이상현상을 방지하는 기법이다.
\ No newline at end of file
diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture21] db \355\205\214\354\235\264\353\270\224 \354\204\244\352\263\204 \354\236\230\353\252\273\355\225\230\353\251\264 \353\260\234\354\203\235\355\225\230\353\212\224 \353\254\270\354\240\234/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture21] db \355\205\214\354\235\264\353\270\224 \354\204\244\352\263\204 \354\236\230\353\252\273\355\225\230\353\251\264 \353\260\234\354\203\235\355\225\230\353\212\224 \353\254\270\354\240\234/README.md"
new file mode 100644
index 0000000..58c7c9d
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture21] db \355\205\214\354\235\264\353\270\224 \354\204\244\352\263\204 \354\236\230\353\252\273\355\225\230\353\251\264 \353\260\234\354\203\235\355\225\230\353\212\224 \353\254\270\354\240\234/README.md"
@@ -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 값을 줄일 수 있는 방향으로 설계
+- 다만, 성능 향상을 위해 일부러 테이블을 나누지 않을 수 도 있다 (비정규화, 반정규화)
\ No newline at end of file
diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture22] db \354\240\225\352\267\234\355\231\224\354\235\230 \352\267\274\353\263\270 (functional dependency)/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture22] db \354\240\225\352\267\234\355\231\224\354\235\230 \352\267\274\353\263\270 (functional dependency)/README.md"
new file mode 100644
index 0000000..9dc524d
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture22] db \354\240\225\352\267\234\355\231\224\354\235\230 \352\267\274\353\263\270 (functional dependency)/README.md"
@@ -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를 결정지을 수 없는 경우
\ No newline at end of file
diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture23] db \354\240\225\352\267\234\355\231\224 (1NF, 2NF)/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture23] db \354\240\225\352\267\234\355\231\224 (1NF, 2NF)/README.md"
new file mode 100644
index 0000000..5ffbe3a
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture23] db \354\240\225\352\267\234\355\231\224 (1NF, 2NF)/README.md"
@@ -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
\ No newline at end of file
diff --git "a/\354\234\244\354\204\261\355\225\230/[lecture24] db \354\240\225\352\267\234\355\231\224 (3NF, BCNF, \354\227\255\354\240\225\352\267\234\355\231\224)/README.md" "b/\354\234\244\354\204\261\355\225\230/[lecture24] db \354\240\225\352\267\234\355\231\224 (3NF, BCNF, \354\227\255\354\240\225\352\267\234\355\231\224)/README.md"
new file mode 100644
index 0000000..7c9e7c0
--- /dev/null
+++ "b/\354\234\244\354\204\261\355\225\230/[lecture24] db \354\240\225\352\267\234\355\231\224 (3NF, BCNF, \354\227\255\354\240\225\352\267\234\355\231\224)/README.md"
@@ -0,0 +1,13 @@
+### Transitive FD
+
+X → Y 이고 Y → Z 가 성립한다면 X → Z 는 transitive FD이다
+- Y와 Z 모두 어떤 key에 대해서도 부분집합이 아니여야 한다
+
+
+| 정규형 | 설명 |
+| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **3NF** | - 기본 키에 의존하지 않는 열을 제거
- non-prime attribute와 non-prime attribute 사이에는 FD가 있으면 안된다
- 모든 non-prime attribute는 어떤 key에도 transitively dependent하면 안된다 |
+| **BCNF** | - 모든 결정자는 후보 키여야 한다
- 모든 유효한 non-trivial FD[^1] X → Y는 X가 super key여야 한다 |
+
+
+[^1]: Y가 X의 부분 집합이 아닌 FD
\ No newline at end of file