4_Database
- 일정한 규칙 혹인 규약을 통해 구조화되어 저장되는 데이터 모음
- 실시간 접근과 동시 공유 가능
- DBMS: 데이터 베이스를 제어, 관리하는 통합 시스템
- DB <-> DBMS <-> Application
- 각 DBMS마다 정의된 쿼리 언어로 접근
- 릴레이션
- 데이터베이스에서 정보를 구분하여 저장하는 기본 단위
- 관계형 DB의 테이블, 비관계형 DB의 콜렉션
- MySQL: 레코드-테이블-DB
- NoSQL: 도큐먼트-컬렉션-DB
- 엔터티 (레코드, 튜플)
- 사람, 장소, 물건, 사건, 개념 등 여러 개의 속성을 지닌 명사
- 강한 엔터티/약한 엔터티(엔터티 존재 여부에 따라 종속적)
- ex. 건물(강한 엔터티)-방(약한 엔터티)
- 속성 (필드)
- 릴레이션에서 관리하는 구체적이며 고유한 이름을 갖는 정보
- '차'라는 엔터티 > 차 넘버, 바퀴 수, 차 색깔 등
- 릴레이션에서 관리하는 구체적이며 고유한 이름을 갖는 정보
- 도메인
- 릴레이션의 각각의 속성들이 가질 수 있는 값의 집합
- 성별이라는 속성: {남, 여}
- 릴레이션의 각각의 속성들이 가질 수 있는 값의 집합
여러 개의 테이블이 있고, 이러한 테이블은 서로의 관계가 정의됨
- 1:1 관계
- 테이블이 하나씩 연결되어 있는 관계
- 테이블을 두 개의 테이블로 나눠 테이블의 구조를 더 이해하기 쉽게 만듬
- ex. 유저 테이블 - 유저 이메일 테이블
- 1:N 관계
- 테이블 하나에 여러 개의 테이블이 연결
- ex. 유저 테이블 - 상품 테이블
- N:M 관계
- 테이블을 직접적으로 연결하여 구축하지는 않음
- 1:N, 1:M 관계를 맺는 테이블 2개로 나누어 설정
- ex. 학생 테이블 - 학생_강의 테이블 - 강의 테이블
- 유일성: 중복되는 값이 없음
- 최소성: 필드를 조합하지 않고, 최소 필드만 써서 키 생성
- 기본키
- 최소성, 유일성 만족
- 자연키: 자연스레 뽑다가 나오는 키. 언젠가는 변하는 속성
- 인조키: 인위적으로 생성한 키. 변하지 않음. 유저ID
- 후보키
- 기본키가 될 수 있는 후보. 최소성, 유일성 만족
- 대체키
- 후보키가 두 개 이상일 경우 하나를 기본키도 지정하느 남은 후보키
- 슈퍼키
- 유일성을 갖춘 키
- 외래키
- 다른 테이블의 기본키를 그대로 참조하는 값
- 중복되어도 괜찮음
- 개체와 개체 간의 관계를 시각적으로 표현
- 가장 기초적으로 DB를 구성할 때 활용
- 시스템의 요구 사항을 기반으로 작성
- NoSQL DB를 표현할 수는 없음
- 정규화 및 성능 향상을 위한 설계 결정에 도움
- 중복을 최소화하고 데이터의 일관성을 유지하기 위해 테이블을 분해하는 과정
- 성능은 좋아질 수도 있고, 나빠질 수도 있음
- 원칙
- 같은 의미를 표현하는 릴레이션이지만 좀 더 좋은 구조로 구성
- 자료의 중복성 감소
- 독립적인 관계는 별개의 릴레이션으로 표현
- 테이블의 속성들이 원자 값으로 구성되어야 함
- 다중 값 속성을 단일 값 속성으로 분리하고, 중첩된 테이블을 생성하여 반복되는 그룹을 제거
- 예시
- 기존
유저번호 유저ID 수강명 성취도 1 홍철 {코딩테스트,프런트특강} {90%,10%} 2 범석 {코드포스특강, DS특강} {7%,8%} - 제 1정규형 적용
유저번호 유저ID 수강명 성취도 1 홍철 코딩테스트 90% 1 홍철 프런트특강 10% 2 범석 코드포스특강 7% 2 범석 DS특강 8%
- 기존
- 이상 현상
- 삽입 이상: 유저를 찾을 때, 유저번호와 유저 ID를 알아야 함 (불필요)
- 수정 이상: 1번 학생이 유저ID를 변경할 때, '홍철'인 행을 모두 변경해야 함.
- 삭제 이상: 홍철 학생이 코딩테스트 수강을 취소하면 해당 과목에 대한 정보가 모두 사라짐, 다시 따로 등록해야하는 번거로움
- 제 1정규형 + 부분함수의 종속성 제거 > 완전 함수 종속
- 함수 종속성: A가 주어지면 B 값이 유일하게 정해진다면 A는 B에 종속 (과목코드, 과목명)
- 부분 함수 종속성: 비기본 키 속성들이 기본 키 전체에 의존하는 것이 아니라 기본 키의 일부에만 의존해야 함
- 완전 함수 종속: 기본 키가 모든 비 기본값을 결정
- 예시
-
기존
주문 번호와 제품명에 종속되지 않는 제조사, 제조사 위치가 있음.주문 번호 제품명 제조사 제조사 위치 배송여부 1 컴퓨터 ABC 미국 Y 1 프린터 XYZ 일본 N 2 컴퓨터 ABC 미국 Y 2 마우스 XYZ 일본 Y 3 컴퓨터 ABC 미국 N -
제 2정규형 적용
주문 번호 제품명 배송여부 1 컴퓨터 Y 1 프린터 N 2 키보드 Y 2 마우스 Y 3 컴퓨터 N 제품명 제조사 제조사 위치 컴퓨터 ABC 미국 프린터 XYZ 일본 마우스 XYZ 일본
-
- 이상 현상
- 삽입 이상: 새로운 제조사(+제조사 위치)를 추가하고 싶은데, 제품명을 NULL로 넣어야 함
- 수정 이상: 제조사 위치를 변경할 때 같은 제조사의 위치를 모두 변경해야 함
- 삭제 이상: 유일한 제조사를 가진 행을 삭제할 경우, 제조사의 정보가 모두 사라짐
- 제 2정규형 + 기본키가 아닌 모든 속성이 이행적 함수 종속을 만족하지 않는 상태
- 이행적 함수 종속: A>B, B>C일 때, A>C인 상태
- 예시
-
기존
제품명 > 제조사, 제조사 > 제조사 위치, 제품명 > 제조사 위치제품명 제조사 제조사 위치 컴퓨터 ABC 미국 프린터 XYZ 일본 마우스 XYZ 일본 -
제 3정규형 적용
제품명 제조사 컴퓨터 ABC 프린터 XYZ 마우스 XYZ 제조사 제조사 위치 ABC 미국 XYZ 일본
-
- 제 3정규형 + 함수 종속 관계에서 모든 결정자가 후보키인 상태
유저ID | 수강명 | 강사 |
---|---|---|
홍철 | 코딩테스트 | 큰돌 |
홍철 | MEVM | 재엽 |
범석 | 코딩테스트 | 큰돌 |
범석 | MEVN | 가영 |
조건
- 각 수강명에 대해 한 학생은 오직 한 강사의 강의만 수강한다
- 각 강사는 한 수강명만 담당한다. (강사: 결정자)
- 한 수강명은 한 강사 또는 여러 강사가 담당할 수 있다. (강사: 후보키 X)
이상 현상
- 삽입 이상: 수강생이 없는 수강을 삽입이 불가능
- 수정 이상: 교수가 수강명을 변경하면 모두 변경
- 삭제 이상: 강사 정보 삭제가 유저 ID 삭제로 이어질 수 있음
유저ID | 강사 |
---|---|
홍철 | 큰돌 |
홍철 | 재엽 |
범석 | 큰돌 |
범석 | 가영 |
수강명 | 강사 |
---|---|
코딩테스트 | 큰돌 |
MEVM | 재엽 |
코딩테스트 | 큰돌 |
MEVN | 가영 |
- 개념적 모델링을 중심으로 DB 구조를 정의하는 과정
- 테이블, 열, 제약 조건 등을 포함하는 데이터베이스 스키마를 정의
- 과정
- 개체를 테이블로 변환
- 개체>테이블 / 속성>열 로 매핑
- 관계를 외래 키로 변환
- 관계는 테이블 간의 관계로 변환 (1:1, 1:N, N:N)
- 관계의 매핑을 위해 외래 키(다른 테이블의 기본 키를 참조하는 열)를 사용합니다.
- 테이블 간의 관계와 제약 조건 정의
- 일관성과 무결성을 유지하기 위해 기본 키, 외래 키, 고유 제약 조건을 정의
- 개체를 테이블로 변환
- 데이터의 정확성, 일관성, 유효성을 유지하는 것
- 현실 세계의 실제 값이 일치하는 지 신뢰에 바탕이 됨
- 종류
- 개체 무결성: 기본 키(primary key)의 고유성과 널(null) 값의 허용 여부를 확인
- 참조 무결성: 서로 참조 관계의 두 테이블의 데이터는 항상 일관된 값 유지
- 도메인 무결성: 속성에 대해 고유한 값을 가지도록 조건이 주어지면 속성 값은 모두 고유한 값을 가짐
- 논리적 기능을 수행하기 위한 작업의 단위
- ACID 특징을 가짐
- 원자성, 일관성, 독립성, 지속성
- 모두 수행되었거나 수행되지 않았거나를 보장 (all or nothing)
- 외부 API 호출 주의 (만약 있다면 롤백 시 어떻게 해야 할 것인지 해결 방법 생각)
- 예시
- 홍철 잔고를 조회한다
- 홍철 잔고에서 500만원을 뺀다
- 규영에게 500만원을 넣는다
여기서 2번까지 수행되고, 3번이 수행되지 않으면 문제가 발생
- 데이터의 무결성 보장
- 커밋: 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어. 변경 내용이 영구적으로 저장됨
- 롤백: 에러나 이슈로 인해 커밋 전 상태로 되돌림
- 허용된 방식으로만 데이터를 변경해야하는 것
- DB의 모든 데이터는 여러 가지 조건, 규칙에 따라 유효함을 가져야 함
- 예시
- 홍철이가 통장에 0원이 있을 때, 500만원을 뺄 수 없음 (통장 잔액은 양수의 값을 가져야하기 때문)
- 트랜잭션 수행 시 서로 끼어들지 못하는 것
- 복수의 병렬 트랜잭션이 마치 순차적으로 실행되는 것처럼 동작
격리 수준 | Dirty Read | Non-Repeatable Read | Phantom Read |
---|---|---|---|
Read Uncommitted | O | O | O |
Read Committed | - | O | O |
Repeatable Read | - | - | O |
Serializable | - | - | - |
격리 수준
- Serializable
- 가장 높은 수준의 격리
- 트랜잭션을 순차적으로 진행
- 트랜잭션이 동시에 같은 행에 접근할 수 없음
- 성능이 떨어지고, 교착 상태가 일어날 확률이 높음
- Repeatable_Read
- Phantom Read(추가되는 행은 막지 않음) 를 허용
- 발생하는 현상 예시
- 사용자 A가 age가 12 이상인 회원을 조회 > 3개 테이블 조회
- 사용자 B가 age가 15인 회원 삽입
- 사용자 A가 다시 조회 > 4개 테이블 조회
- 발생하는 현상 예시
- Phantom Read(추가되는 행은 막지 않음) 를 허용
- Read_Committed
- 가장 많이 사용되는 격리 수준
- 커밋 완료된 데이터에 대해서만 조회를 허용
- Phantome Read, Non-Repeatable Read(행 값이 변경될 수 있음) 허용
- 발생하는 현상 예시
- 사용자 A가 age가 12 이상인 회원을 조회 > 3개 테이블 조회
- 사용자 B가 age가 15인 회원 삽입
- 사용자 A가 다시 조회 > 4개 테이블 조회
- 발생하는 현상 예시
- Read_Uncommitted
- 트랜잭션이 커밋되기 전 다른 트랜잭션에 노출되는 문제가 있음
- 가장 빠르다
- 몇몇 행이 제대로 조회되지 않더라도 괜찮은 거대한 양의 데이터를 '어림잡아' 집계하는 데 좋음
- 성공적으로 수행된 트랜잭션은 영원히 반영
- 시스템에 장애가 발생해도 원래 상태로 복구하는 회복 기능 필요
- 체크섬 (중복 검사의 형태. 오류 정정을 통해 송신된 자료의 무결성 보호)
- 저널링 (변경 사항을 커밋하기 전에 로깅)
- 롤백
- 행과 열을 가지는 표 형식의 데이터를 저장
- SQL 언어 활용
- 대부분의 운영 체제와 호환
- 가장 많이 사용하는 DB (커뮤니티가 잘 발달됨)
- C, C++으로 개발, B-트리 기반의 인덱스, 스레드 기반의 메모리 할당 시스템, 매우 빠른 조인, 최대 64개의 인덱스 제공
- 롤백, 커밋, 이중 암호 지원 보안 등의 기능 제공
- 데이터 행마다 버전관리가 진행
- 과거 행을 삭제하고, 변경된 데이터를 추가해야함으로 성능이 좋지 않고, 필요없는 데이터를 장치인 VACUUM 작업이 주기적으로 필요
- 최대 테이블의 크기는 32TB
- SQL, JSON을 이용하여 데이터 접근 가능
- 지정 시간에 복구, 로깅, 접근 제어, 중첩된 트랜잭션, 백업 등의 기능 제공
- 복잡한 쿼리 요구에 유리
- 관계형 DB를 지양하며, 스키마가 없거나 느슨한 스키마를 제공하는 저장소
- 복잡한 구조를 쉽게 저장할 수 있음
- 대량의 분산된 데이터를 저장하고, 조회하는데 특화됨
- 가장 기본적인 형태. 저장과 조회라는 가장 간단한 원칙에 충실한 DB.
- 값에 모든 데이터 타입을 허용함 → 개발자들이 데이터 입력 단계에서 검증로직을 제대로 구현해야 함
- Redis. AWS DynamoDB.
- key-value Model의 확장한 구조. 여기서 문서란 JSON이나 XML같은 표준 형식을 가진 문서이다. (Key-Value와 차이점)
- B 트리 인덱스를 사용하여 2차 인덱스를 생성한다.
- 쓰기의 성능이 떨어짐
- 이상적인 상황 = 읽기:쓰기 = 7:3
- MongoDB.
- Row형으로 저장하는 대신 Column으로 저장하는 방식
- 하나의 키에 여러 개의 칼럼 이름과 칼럼 값의 쌍으로 이루어진 데이터를 저장하고 조회
- 저장의 기본 단위: Column
- Column 수가 많다면 이를 묶어 Column Family로 구성한다.
- 다수의 클러스터에서 운영된다. 만약 단일서버에서 운영해도 될만큼 데이터가 적다면 적합하지 않다.
- 읽기보다 쓰기에 특화되어 있다. 빠른 시간 안에 대량의 데이터를 입력하고 조회하는 서비스를 구현할 때 가장 좋은 성능을 보인다.
- BigTable. Cassandra. HBase.
구분 | 관계형 DB | NoSQL DB |
---|---|---|
데이터 저장 | SQL을 통해서 테이블에 저장 | 다양한 형식으로 데이터를 저장 |
스키마 | 고정된 형식의 스키마가 필요 | 동적으로 스키마 형태를 관리 |
쿼리 | 테이블 형식과 관계에 맞춰 데이터를 요청(구조화) | 데이터 그룹 자체를 조회(비구조화/속도가 느림) |
확장성 | 수직적으로 확장(복잡하고, 시간 많이 소모) | 수평적 확장(많은 트래픽 편리하게 관리) |
데이터 처리 | 정렬,탐색,분류가 빠름 | 쓰기와 읽기 성능이 빠름 |
- ACID 성질을 준수하는 경우
- 트랜잭션에 의한 상태의 변화를 수행하는 과정에서 안정성을 보장
- 예외적인 상황을 줄이고, 무결성을 보호
- 전자 상거래 등에 자주 쓰임
- 데이터가 구조적이고 일관된 경우
- 규모가 많은 서버를 필요로 하지 않고 일관된 데이터를 사용하는 경우
- 데이터 구조가 거의 없는 대용량 데이터 저장하는 경우
- 데이터 유형에 제한이 없음
- 수평적 확장이 가능하여 효율적인 트래픽 처리 가능
- 빠르게 서비스를 구축하는 과정에서 구조를 자주 업데이트하는 경우
- 시장에 빠르게 프로토타입을 출시해야하는 경우
- 적절한 인덱스 생성:검색 속도 향상
- 쿼리 튜닝: 쿼리 실행 계획을 분석하고 인덱스를 최적화하거나 조인 방식을 변경하여 쿼리의 성능을 향상
- 데이터베이스 캐싱: 데이터베이스의 자주 액세스되는 데이터를 메모리에 캐시하여 접근 속도를 향상
- 파티셔닝: 대용량의 테이블을 파티셔닝하여 작은 조각으로 나누는 것은 쿼리의 성능을 향상
- 트랜잭션 관리
- 적절한 하드웨어 구성
- 정규화와 역정규화
- 추가적인 저장 공간을 활용하여 DB 테이블의 검색 속도를 향상시키기 위한 자료구조
- 만약 DB 테이블의 모든 데이터를 검색해서 원하는 결과를 가져오려면 시간이 오래 걸림
- 특정 열의 값과 해당 레코드의 주소를 가진 인덱스를 만들어 데이터 탐색을 빠르게 한다.
- 장점
- 테이블 조회하는 속도 향상
- 시스템 부하를 줄임
- 단점
- 추가 저장 공간 필요
- 정렬된 상태를 유지하기 위해 추가 작업 필요
- 잘못 활용할 경우, 역효과
- 권장 케이스
- 데이터 양이 많은 테이블
- 업데이트보다 조회가 잦은 테이블
- 조건문이나 정렬이 잦은 테이블
- 인덱스는 비용
- 인덱스는 두 번 탐색 (인덱스 리스트 > DB 테이블)
- 테이블 수정 시, 인덱스도 수정되어야함
- 항상 테스팅하라
- 서비스마다 최적의 인덱스는 다르다
- 복합 인덱스를 신경쓰자
- 여러 필드를 기반으로 조회 할 때 복합 인덱스 생성
- 순서가 있고, 생성 순서에 따라 인덱스 성능이 달라짐
- 같음(==) > 정렬 > 다중 값 > 카디널리티 (유니크한 값의 정도)
Category | PK | Index |
---|---|---|
목적 | 데이터 중복을 막기 위함 | 검색을 속도 개선을 위함 (중복 허용) |
데이터 | 데이터 내에 존재함 | 별도의 디스크 공간에 존재함 (인덱스 테이블) |
검색 | 모든 데이터를 불러와야함 | Index 데이터만 가져와서 원하는 값을 얻을 수 있음 |
- 자식 노드 2개 이상의 균형 트리 (비균형일 때 균형을 맞출 필요가 있음)
- Root/Branch/Leaf Node로 나뉨
- 하향식 검색을 수행
- 부모 노드 요소 개수보다 자식 노드가 많아지면 부모 노드로 중앙 값을 부모 노드로 올림
삽입과 제거: https://rebro.kr/169
- B-Tree의 확장
- 리프 노드만 인덱스-값을 가짐. Linked List로 연결됨
- 리프 노드에서 선형 탐색
- 한 노드에 많은 key를 담을 수 있어 트리 높이가 낮아짐
- 특정 값을 해시 함수에 입력하면 해당 값에 대한 인덱스 위치가 계산되어 빠른 검색이 가능
- <, LIKE, BETWEEN 등의 범위 조건문은 사용할 수 없음
- 실행 속도가 느린 쿼리를 최적화하여 성능을 향상시키는 과정
- 단계
- 쿼리 실행 계획 분석: 데이터베이스 시스템은 쿼리를 실행하기 위해 실행 계획을 생성하는데, 이 계획은 쿼리의 최적 실행 경로를 결정
- 인덱스 분석: 쿼리가 자주 사용하는 조건에 해당하는 인덱스가 존재하는지 확인
- 조인 최적화: 조인 조건을 최적화하여 조인 연산의 효율성을 높이고 중복되는 작업을 피할 수 있음. 조인 방식을 변경하거나 필요에 따라 조인 힌트를 사용할 수 있음.
- 서브쿼리 최적화: 서브쿼리를 적절히 최적화하고 필요에 따라 인라인 뷰 등으로 변경하여 실행 속도를 향상
- 데이터베이스 통계 최적화: 테이블의 행 수, 칼럼의 고유 값 수 등의 통계 정보를 업데이트하여 실행 계획을 더 정확하게 생성
- 중첩 루프 조인
- 중첩 for문 + 조건에 맞는 조인
- 랜덤 접근에 의한 비용이 많은 증가 (대용량에서 부적절)
for each row in t1 matching reference key{ for each row in t2 matching reference key{ if row satisfies join conditions, send to client } }
- 정렬 병합 조인
- 조인할 필드 기준으로 정렬하고 정렬이 끝난 이후에 조인 작업
- 적절한 인덱스가 없고, 조인 조건으로 범위 비교 연산자(<,>)가 있을 때 사용
- 해시 조인
- 해시 테이블 사용
- 동등(==) 조건에서만 사용
- 테이블을 한번씩만 읽어 중첩 루프 조인보다 보통 성능이 좋음
- 과정
- 빌드 단계
테이블 하나를 메모리에 온전히 삽입 (비교적 작은 테이블) - 프로브 단계
레코드 읽기를 통해 기준과 일치하는 레코드를 찾아 결괏값 반환
- 빌드 단계
- 리팩토링을 통해 시간을 줄이고, SQL 튜닝을 통해 속도 보장
-
인덱스를 타지 않는 경우
- 대부분 좌변을 가공하는 경우
- 상수나 우변을 가공할 방법을 모색해야함
select * from TB where TRIM(USER_NO)='0001' --인덱스를 타지 않음 select * from TB where USER_NO='0001'
-
IN vs EXISTS
- 두 연산 모두 해당하는 값이 있는지에 대해 확인하는 연산
- IN(모든 집합에서 충족한 집합을 찾아냄), EXISTS(명시된 기준을 충족하는 단일 행의 조건)
- EXISTS가 연산에서 더 유리
SELECT * FROM TB A WHERE A.USER_ID IN ( SELECT X.USER_ID FROM TB_USER X ) SELECT * FROM TB A WHERE EXISTS ( SELECT 1 FROM TB_USER X WHERE X.USER_ID=A.USER_ID )
-
JOIN의 순서를 생각하지 않은 경우
- 작은 것부터 연산하는 것이 성능상 유리
SELECT * FROM TB_USER a INNER JOIN TB_ORDER B --USER 테이블과 ORDER 테이블은 1:N관계. ON A.USER_ID = B.USER_ID -- INNER JOIN을 통해 테이블을 작게 만든다 WHERE B.ORDER_DT = '20210101' -- 그 후 조건문 사용