diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture25] db \354\235\270\353\215\261\354\212\244/README.md" "b/\352\271\200\354\227\260\354\232\261/[lecture25] db \354\235\270\353\215\261\354\212\244/README.md" new file mode 100644 index 0000000..722a550 --- /dev/null +++ "b/\352\271\200\354\227\260\354\232\261/[lecture25] db \354\235\270\353\215\261\354\212\244/README.md" @@ -0,0 +1,132 @@ +> # [Lecture 25](https://www.youtube.com/watch?v=IMDH4iAQ6zM&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=25) + +## 주요 내용 + +- index가 중요한 이유 +- index 거는 법 +- index 동작 방식 +- index 사용 시 참고 사항 + +## index가 중요한 이유 + +- index가 없다면 full scan(= table scan)으로 데이터를 찾아야 하므로 시간 복잡도는 O(N) +- index가 있다면 O(logN) (B-tree based index) +- index를 쓰는 이유 + - 조건을 만족하는 튜플(들)을 빠르게 조회하기 위해! + - 빠르게 정렬(order by)하거나 그룹핑(group by) 하기 위해! + +## index 거는 법 + +```sql +create [unique] index 인덱스명 on 테이블명 (컬럼명); +``` + +- unique 옵션은 중복이 안되는 고유 인덱스를 생성하는 것 + - 생략하면 중복이 허용 +- unique 옵션으로 인덱스를 생성하려면 인덱스를 설정하려는 컬럼 값에 중복이 있으면 안 됨 + +```sql +create table 테이블명 ( + id int primary key, + name varchar(20) not null, + team_id int, + backnumber int, + index 인덱스명 (컬럼명), + unique index 인덱스명 (컬럼명들..), +); +``` + +- primary key에는 index가 자동 생성됨 + +## index 조회 + +```sql +show index from 테이블명; +``` + +## B-tree 기반 인덱스 동작 방식 + +- members table + + + | a | b | c | + | --- | --- | --- | + | 3 | … | … | + | 7 | … | ... | + | 1 | … | … | + | 2 | … | … | + | … | … | … | + | 7 | … | … | + | 9 | … | … | +- index(a) table (members의 a컬럼에 대한 index 테이블) + + + | a | ptr | + | --- | --- | + | 1 | … | + | 2 | … | + | 3 | … | + | 4 | … | + | … | … | + | 13 | … | +- index테이블에서 ptr은 포인터 데이터로 members테이블의 어떤 튜플(행)과 연관있는지 가리키고 있음 +- a = 9 인 튜플을 찾는다고 해보면 index테이블에서 binary search를 통해 a = 9인 것을 찾음 +- a = 7 and b = 95 인 튜플을 찾는다고 하면 똑같이 binary search를 통해 a = 7인 것을 찾지만 그 이후 b를 찾아야 하기 때문에 a를 찾는 것은 이진 탐색이지만 b를 찾는 것은 full scan이 되어버림 + - 그래서 index(a, b)를 생성하여 해결 + - 만약 index(a, b) 테이블을 생성했다면 이것을 이용해서 b에 대한 탐색을 한다 해도 b에 대한 정렬이 제대로 되어 있지 않기 때문에 효율이 나오지 않거나 index가 아예 사용되지 않을 수 있음 (index(b)를 생성해서 탐색해야함) + +## 쿼리가 어떤 index를 쓰는지 확인하기 + +```sql +explain select * from player where backnumber = 7; +``` + +- 만약 index가 여러개 있다고 하자, 그럼 이때 어떤 index를 쓰는 기준은 무엇인가?? + - DBMS에 존재하는 optimizer가 알아서 적절하게 index를 선택함 +- optimizer가 항상 최고의 index를 선택하지는 않음! +- 특정 index를 사용하도록 명시하는 법 + - MySQL + + ```sql + select * from player force index (인덱스명) + where backnumber = 7; + ``` + + - use index도 존재하나 force index가 좀 더 강제적임 (use index는 써 주세용~) + - 만약 해당 인덱스로 데이터를 찾을 수 없다면 full scan을 실시함 + - 특정 인덱스를 제외하고 싶다면 ignore index 사용 + +## index 주의 사항 + +- index가 많다고 좋은건 아님! +- table에 write할 때마다 index도 변경 발생 + - B-tree일 경우 정렬(트리의 구조 조정)을 해야하므로 많은 시간이 걸릴 수 있음 +- 추가적인 저장 공간 차지 +- 즉, 불필요한 index를 만들지 말자 + +## Covering index + +- 조회하는 attribute(s)를 index가 모두 cover할 때를 의미 +- index(team_id, backnumber)가 존재할 때 team_id = 5;인 데이터를 가져온다고 하면 굳이 player 테이블에서 데이터를 가져올 필요가 없음 (index테이블에서 바로 가져오면 됨) +- 조회 성능이 더 빠름!! + +## Hash index + +- hash table을 사용하여 index를 구현 +- 시간복잡도 O(1) +- 하지만 단점 존재!! + - rehashing에 대한 부담 (rehashing : hash table을 더 큰 사이즈로 늘려주는 것) + - index의 equality 비교(==, ≠)만 가능! (range 비교 불가능) + +## full scan이 더 좋은 경우 + +- table에 데이터가 조금 있을 때 (몇 십, 몇 백건 정도) +- 조회하려는 데이터가 테이블의 상당 부분을 차지할 때 + - 남자만 조회, 여자만 조회 .. +- index를 쓸 지 full scan을 할 지는 optimizer가 판단함!! + +## 참고 사항 + +- order by나 group by에도 index가 사용될 수 있음 +- FK에는 index가 자동으로 생성되지 않을 수 있음 (MySQL은 생성되나 다른 RDBMS에는 생성되지 않는 경우가 있음) +- 이미 데이터가 몇 백만 건 이상 있는 테이블에 인덱스를 생성하는 경우 시간이 몇 분 이상 소요될 수 있고 DB 성능에 안 좋은 영향을 줄 수 있음 \ No newline at end of file diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/README.md" "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/README.md" new file mode 100644 index 0000000..d4694b2 --- /dev/null +++ "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/README.md" @@ -0,0 +1,58 @@ +> # [Lecture 28](https://www.youtube.com/watch?v=liPSnc6Wzfk&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=28) + +## 주요 내용 + +- B tree 시간 복잡도 +- B tree가 DB index로 쓰이는 이유 + +## B tree 계열 + +- B+ tree, B* tree +- 시간 복잡도 : O(logN) + +## self-balancing BST + +- 스스로 균형을 잡는 이진 탐색 트리 +- AVL tree, Red-Black tree +- 시간 복잡도 : O(logN) + +## 위 트리를 비교하기 전 DB 관점에서의 내용 정리 + +- DB는 secondary storage에 저장됨 (secondary storage : SSD or HDD) +- DB에서 데이터를 조회할 때 secondary storage에 최대한 적게 접근하는 것이 성능 면에서 좋음 +- secondary storage는 block 단위로 읽고 쓰기 때문에 연관된 데이터를 모아서 저장하면 더 효율적으로 읽고 쓸 수 있음 + +## AVL tree index(b) vs B tree index(b) + +- tree의 각 노드는 서로 다른 block에 있다고 가정 +- 초기에는 root 노드를 제외한 모든 노드는 secondary storage에 있다고 가정 +- 초기에는 데이터 자체도 모두 secondary storage에 있다고 가정 (아직 메인메모리(RAM)에 올라오지 않은 상태) +- AVL tree는 자녀 노드 수가 1~2개 가질 수 있음 +- 5차 B tree는 자녀 노드 수가 3~5개 가질 수 있음 +- 즉, B tree는 데이터를 찾을 때 탐색 범위를 빠르게 좁힐 수 있음 + - 루트 노드에서 부터 리프 노드까지의 거리가 짧음 + - secondary storage에 접근 횟수가 적음 +- AVL tree는 노드의 데이터로 1개 가질 수 있음 +- 5차 B tree는 노드의 데이터로 2~4개 가질 수 있음 +- 즉, B tree는 block 단위에 대한 저장 공관 활용도가 더 좋음 + +## B tree의 강력함 + +- with 101차 B tree + - 자녀 수 : 51~101 + - key 수 : 50~100 +- best case의 데이터 총 수
+ + +- worst case의 데이터 총 수
+ + +- avg case의 데이터 총 수
+ + + +## B tree 계열을 DB index로 사용하는 이유 + +- DB는 기본적으로 secondary storage에 저장됨 +- B tree index는 self-balancing BST에 비해 secondary storage 접근을 적게 함 +- B tree 노드는 block 단위의 저장 공간을 알차게 사용할 수 있음 \ No newline at end of file diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-1.png" "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-1.png" new file mode 100644 index 0000000..95324c3 Binary files /dev/null and "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-1.png" differ diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-2.png" "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-2.png" new file mode 100644 index 0000000..477f633 Binary files /dev/null and "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-2.png" differ diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-3.png" "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-3.png" new file mode 100644 index 0000000..3c58b61 Binary files /dev/null and "b/\352\271\200\354\227\260\354\232\261/[lecture28] B tree/img/lecture28-3.png" differ diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture29] partitioning, sharding, replication/README.md" "b/\352\271\200\354\227\260\354\232\261/[lecture29] partitioning, sharding, replication/README.md" new file mode 100644 index 0000000..8ad0ee7 --- /dev/null +++ "b/\352\271\200\354\227\260\354\232\261/[lecture29] partitioning, sharding, replication/README.md" @@ -0,0 +1,53 @@ +> # [Lecture 29](https://www.youtube.com/watch?v=P7LqaEO-nGU&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=29) + +## 주요 내용 + +- partitioning +- sharding +- replication + +## partitioning + +- 파티셔닝 +- database table을 더 작은 table로 나누는 것 +- partitioning 종류 + - vertical partitioning : column을 기준으로 table을 나누는 방식 + - horizontal partitioning : row를 기준으로 table을 나누는 방식 + +## vertical partitioning + +- board 테이블이 있다고 했을 때 게시글 목록을 보여주는데 content까지 가져올 필요가 없음!! +- 이럴 경우 무거운 데이터인 content같은 것을 따로 분리해서 테이블로 나누는 것 + +## horizontal partitioning + +- 테이블의 크기가 커질수록 인덱스의 크기도 커짐 +- 테이블에 read / write가 있을 때마다 인덱스에서 처리되는 시간도 조금씩 늘어남 +- 한 테이블에만 데이터를 쌓지 않고 테이블을 나누어서 데이터를 분산하여 쌓는 방법을 사용하여 문제를 해결함 +- 즉, hash function을 이용하여 horizontal partitioning을 하여 해결 가능(hash based horizontal partitioning) +- hash function에서 기준이 되는 키(테이블에서 기준이 되는 키)를 partition key라고 함 +- 가장 많이 사용될 패턴에 따라 partition key를 정하는 것이 중요함!!! +- 데이터가 균등하게 분배될 수 있도록 hash function을 잘 정의하는 것도 중요함!!! +- hash-based horizontal partitioning은 한번 partition이 나뉘어져서 사용되면 이후에 partition을 추가하기 까다로움 +- partition들을 같은 DB 서버에 저장함 (HW 자원에 한정될 수 있음) + +## sharding + +- horizontal partitioning처럼 동작 +- horizontal partitioning과 차이는 각 partition이 독립된 DB 서버에 저장됨 (HW 자원에 한정되지 않음) +- 그래서 부하(load)를 분산 시킬 수 있음 +- 즉, 데이터가 많이 쌓이는 테이블에는 샤딩을 사용하여 각 파티션마다 독립된 DB 서버를 할당하고 트래픽을 분산 시켜 DB 서버의 부하를 낮추는 방식을 사용함 + +## replication + +- DB 서버의 데이터를 copy하여 sync를 맞춰 나가 하나의 DB 서버에 문제가 생기더라도 다른 DB 서버(보조 서버)를 통해 문제를 해결하는 방법 +- 기존 DB 서버 : master / primary / leader +- 복사 DB 서버 : slave / secondary / replica +- 즉, 한 서버에 장애가 발생하여도 서비스에 타격이 없도록 하는 고가용성(High availability)을 보장하는 것 +- 또는 계속 되는 트래픽에 대한 부하를 분산시킬 수도 있음!! + +## 정리 + +- partitioning : table을 목적에 따라 작은 table들로 나누는 방식 +- sharding : horizontal partitioning으로 나누어진 table들을 각각의(독립된) DB 서버에 저장하는 방식 +- replication : DB를 복제해서 여러 대의 DB 서버에 저장하는 방식 \ No newline at end of file diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture30] dbcp/README.md" "b/\352\271\200\354\227\260\354\232\261/[lecture30] dbcp/README.md" new file mode 100644 index 0000000..ae99e37 --- /dev/null +++ "b/\352\271\200\354\227\260\354\232\261/[lecture30] dbcp/README.md" @@ -0,0 +1,27 @@ +> # [Lecture 30](https://www.youtube.com/watch?v=zowzVqx3MQ4&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=30) + +## 주요 내용 + +- DBCP란? +- 성능에 도움되는 이유 +- DBCP 튜닝 팁 + +## DBCP + +- DataBase Connection Pool +- connection을 재사용하여 열고 닫는 시간을 절약할 수 있음 + +## DBCP 설정 방법 (Spring hikariCP - MySQL 기준) + +- max_connections (MySQL) : client와 맺을 수 있는 최대 connection 수 +- wait_timeout (MySQL) : connection이 inactive 할 때 다시 요청이 오기까지 얼마의 시간을 기다린 뒤에 close할 것인지를 결정 +- minimumIdle (hikariCP) : pool에서 유지하는 최소한의 idle connection 수 +- maximumPoolSize (hikariCP) : pool이 가질 수 있는 최대 connection 수 (idle과 active(in-use) connection 합쳐서 최대 수) +- idle connection 수가 minimumIdle보다 작고, 전체 connection 수도 maximumPoolSize보다 작다면 신속하게 추가로 connection을 만듦 +- 즉, maximumPoolSize는 Pool에 존재할 수 있는 connection의 최대 수이며 minimumIdle은 Pool에 사용하지 않는 connection이 최소한 몇개는 있어야 된다는 것으로 connection이 maximumPoolSize 미만이고 idle connection이 minimumIdle 미만이라면 connection을 만든다!! +- 기본 값은 maximumPoolSize와 minimumIdle이 동일함 (= pool size 고정) +- maxLifetime (hikariCP) : pool에서 connection의 최대 수명 + - idle connection은 maxLifetime을 넘기면 바로 제거 + - active인 경우라면 maxLifetime을 넘기면 pool로 반환된 후 제거 + - 이 값은 DB의 connection time limit(MySQL에서는 wait_timeout)보다 몇 초 짧게 설정해야 함 +- connectionTimeout (hikariCP) : pool에서 connection을 받기 위한 대기 시간 \ No newline at end of file diff --git "a/\352\271\200\354\227\260\354\232\261/[lecture31] NoSQL/README.md" "b/\352\271\200\354\227\260\354\232\261/[lecture31] NoSQL/README.md" new file mode 100644 index 0000000..845bbaa --- /dev/null +++ "b/\352\271\200\354\227\260\354\232\261/[lecture31] NoSQL/README.md" @@ -0,0 +1,41 @@ +> # [Lecture 31](https://www.youtube.com/watch?v=sqVByJ5tbNA&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=31) + +## 주요 내용 + +- NoSQL이란? +- RDB vs NoSQL +- MongoDB +- Redis + +## RDB 단점 + +- 경직된 스키마 / 유연한 확장성의 부족 (새로운 기능이 추가될 때마다 컬럼을 추가해야하는 상황이 발생하기도 함) +- 정규화로 인한 과도한 조인과 성능 하락 +- scale-out이 쉽지 않음 (여기서의 scale-out은 DB 서버를 추가하는 것) +- ACID를 보장하려다 보니 DB 서버의 performance에 영향을 줌 + +## NoSQL + +- Not only SQL +- mongoDB, redis, DynamoDB … + +## NoSQL 특징 + +- 유연한 스키마 / 스키마 관리를 application 레벨에서 함 (개발자가 부담) +- 데이터 중복 허용 (join 회피) +- scale-out이 쉽고 편함 (서버 여러 대로 하나의 클러스터를 구성하여 사용) +- ACID의 일부를 포기하고 high-throughput, low-latency 추구 (금융 시스템처럼 consistency가 중요한 환경에서는 사용하기가 조심스러움) + +## Redis + +- in-memory key-value database, cache … +- 메모리로도 사용하기도 하고 캐시로도 사용하기도 하고 … +- data type : string, list, set, hash, sorted set … +- hash-based sharded cluster +- High Availability (replication, automatic failover) +- in-memory로 SSD와 HDD보다 빠르기 때문에 주로 cache처럼 사용함 +- 기본 동작 과정 + 1. 백앤드에서 redis에 데이터가 있는지 확인 (redis에 데이터 존재하지 않음) + 2. 백앤드에서 DB에 데이터가 있는지 확인 (DB에 데이터 존재) + 3. 백앤드에서 가공하여서 프론트로 보여줌과 동시에 redis에 데이터를 key-value 형태로 저장 + 4. 1~3번 반복 \ No newline at end of file