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