- CHAR : 고정형 문자열(n <= 255)
- 자식 노드가 2개 이상인 B-Tree를 개선시킨 자료구조입니다.
- B-Tree 리프노드들을 LinkedList로 연결하여 순차 검색을 용이하게 합니다. 해시테이블보다 나쁜 O(lon2N)의 시간 복잡도를 갖지만 일반적으로 사용되는 자료구조입니다.
- 컬럼의 값으로 생성된 해시를 기반으로 인덱스를 구현합니다.
- 시간 복잡가 O(1)이라 검색이 매우 빠릅니다.
- 부등호와 같은 연속적인 데이터를 위한 순차 검색이 불가능하기 때문에 사용에 적합하지 않습니다.
인덱스 : 검색 속도를 높이기 위한 색인 기술
- 일반적으로 SQL 서버에서 데이터 저장할 때 내부적으로 아무런 순서없이 저장 (Heap이라는 곳)
- 풀스캔, 테이블 스캔 : 인덱스가 없는 테이블의 데이터를 찾을 때, 전체 데이터 페이지를 처음 레코드부터 끝 페이지 마지막까지 조회한다
핵심적인 기준 4가지
- Cardinality : 데이터 집합의 유니크한 원소 갯수
수정 빈도: 수정 빈도가 낮으면 인덱스 설정 컬럼에 좋다. 자주 안바뀌는 것이 좋다.
- 완전 함수 종속 : 기본키의 부분집합이 다른 값을 결정하지 않는 것을 의미
- 이행적 종속 : A
->
B, B->
C 일 때, A->
C가 성립하는 것을 의미
BCNF 정규형 : 제 3정규형을 만족하고, 모든 결정자가 후보키가 되도록 분해합니다.
- 삽입 이상 : 자료를 삽입할 때 특정 속성에 해당하는 값이 없어 NULL을 입력해야 하는 현상
- 갱신 이상 : 중복된 데이터 중 일부만 수정되어 데이터 모순이 일어나는 현상
- 삭제 이상 : 어떤 정보를 삭제하면, 다른 데이터도 삭제되는 현상
- 엔티티를 식별하는 대표 key
- Null 값을 가질 수 없고 중복된 값을 가질 수 없다.
- Table당 1개만 지정해야한다.
- 외부 식별자 key로 테이블 간의 관계를 의미한다.
- 두 테이블 간의 종속이 필요한 관계이면 그 접점이 되는 컬럼을 FK로 지정하여 서로 참조할 수 있도록 관계를 맺어준다.
- 테이블 간의 잘못된 매핑을 방지하는 역할도 있다.
- 장점 : 스키마에 맞춰 데이터를 관리하기 때문에 데이터의 정합성을 보장할 수 있다.
- 단점 : 시스템이 커질 수록 쿼리가 복잡해지고 성능이 저하되며 Scale-out이 어렵다.(장비를 추가해서 확장) (Scale-Up만 가능 : 용량, 사양을 높이는 것)
- 장점
- 스키마없이 Key-Value 형태로 데이터를 자유롭게 관리할 수 있다.
- 데이터 분산이 용이하여 Scale-Out, Scale-Up 모두 가능하다.
- 단점
- 데이터 중복이 발생할 수 있고, 중복된 데이터가 변경될 경우 모든 컬렉션에서 수정을 수행해야 한다.
- 스키마가 존재하지 않기 때문에 명확한 데이터 구조를 보장하지 않아 데이터 구조 결정이 어려울 수 있다.
- Logstash : 다양한 소스(DB, csv 파일 등)의 로그 또는 트랜잭션 데이터를 수집, 집계, 파싱하여 Elasticsearch에 전달
- Elasticsearch : Logstash로부터 받은 데이터를 검색 및 집계를 하여 필요한 관심 있는 정보를 획득
- Kibana : Elasticsearch의 빠른 검색을 통해 데이터를 시각화 및 모니터링
- 역색인 구조(Inverted Index) : 특정 키워드를 포함하고 있는 문서들에 대한 Primary Key를 매핑하는 인덱스 테이블을 생성하고, 이 테이블을 이용해 빠른 문서 탐색을 가능하게 합니다.
- BTree(B-Tree를 개선시킨 자료구조), Trie(문자열 집합 트리 자료구조), Hash Table(해시함수 기반의 key-value 자료구조)로 주로 구현됨
리플리케이션은 비동기 방식으로 데이터를 동기화한다.
- DB 요청의 대부분이 읽기 작업이기 때문에 충분히 성능을 높일 수 있다.
- 비동기 방식으로 지연 시간이 거의 없다
- 노드 간 데이터 동기화가 보장되지 않아 일관성있는 데이터를 얻지 못할 수도 있다.
- Master 노드가 다운되면 복구 및 대처가 까다롭다.
동기 방식으로 노드들 간의 데이터를 동기화한다.
- 노드들 간의 데이터를 동기화하여 항상 일관성있는 데이터를 얻을 수 있다.
- 1개 노드가 죽어도 다른 노드가 살아 있어 시스템을 계속 장애없이 운영할 수 있다.
- 여러 노드들 간의 데이터를 동기화하는 시간이 필요하므로 리플리케이션에 비해 성능이 떨어진다.
- 장애가 전파된 경우 처리가 까다롭고, 데이터 동기화에 의해 스케일링에 한계가 있다.
- Active-Active : 클러스터를 항상 가동하여 가동 가능한 상태로 두는 구성 방식
- Active-Standby : 일부 클러스터는 가동하고, 일부 클러스터는 대기 상태로 구성하는 방식
- Hot-Standby : 평소에도 Standby DB 작동, 비용이 더 많이 듬
- Cold-Standby : Active DB가 다운된 시점에 작동
- Dirdy Read 발생
- Dirty Read : write 트랜잭션이 데이터를 업데이트만 하고 커밋은 안했는데 read 트랜잭션이 해당 값을 읽고 write 트랜잭션이 롤백한 상황, 이 상황에서 다시 read 트랜잭션이 re-read 할 때 생김
- 커밋된 것은 Undo 공간에 있어서 다른 read 트랜잭션이 오면 백업된 것을 리턴해준다.
- 해당 격리 레벨부터 Spring에서 undo 영역을 이용한 MVCC(Multiversion Concurrency Control)를 사용하여 Consistence Read를 보장해줍니다.
- 커밋하기 전 작업 중인 데이터의 값을 읽을 수 없고, 읽기 트랜잭션이 끝나기 전까지 Undo 영역을 타 트랜잭션에서 쓰기 작업 후 커밋한 데이터로 덮어쓸 수 없다. 즉 선행 트랜잭션이 읽은 데이터를 종료까지 갱신/삭제 안됨
- Phantoom read 가능성 : 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안보였다가 하는 현상 > 쓰기 잠금이 필요하다.
위 그림에서는 리턴값이 달라지는 것에 집중하여 보자.
SERIALIZABLE : 트랜잭션을 다른 트랜잭션으로부터 완전히 분리시킨다. 특정 트랜잭션을 작업하는 동안 타 트랜잭션은 별로의 작업을 할 수 없다, insert문까지 금지
- @Transactional 어노테이션만 붙여주면 jdbc 기본 isolation level을 따름
- MYSQL : 2, ORACLE : 1, MariaDB : 2
- thread-safe 하긴 하지만 여러 개의 인스턴스가 있으니 의미가 없다. 이럴 때는 아래 DB 락을 고려해봐야한다.
- exclusive lock을 걸어 다른 트랜잭션이 접근할 수 없게 한다.
- 격리 수준을 높여서 데이터 무결성을 보장하는 수준이 높지만, 다른 트랙잭션을 막아 성능상 좋지 않고, 데드락이 발생할 수 있다.
- 실제로는 lock을 사용하지 않고 버전을 이용해 데이터 정합성을 맞춘다.
- 데이터 동시성 문제가 빈번하지 않다면 낙관적 lock이 성능이 좋습니다.
- 잦은롤백 처리 > 성능 악화를 일으킬 수 있습니다.
while (true) {
try {
optimisticStockService.decrease(id, quantity);
break;
} catch (Exception e) {
Thread.sleep(50);
}
}
- 트랜잭션이 종료될 때 자동으로 락 해제가 안되서 별도의 락 해제 명령어를 사용하거나 선점 시간이 끝나야한다.
- Pessimistic lock과 비슷하지만, row, 테이블 단위가 아니라 metadata 단위로 락을 건다.
- named lock이 같은 데이터 소스를 사용하면 커넥션 풀이 부족하는 현상이 발생할 수 있다. 실무에서는 데이터 소스를 분리해서 사용해야한다.
MongoDB에 대해서 간단히 설명해주세요.
CAP 이론과, Eventual Consistency에 대해서 설명해주세요.
Reference: