📚 Database
기존에는 파일 시스템을 이용하여 데이터를 관리하였으나 파일 시스템의 문제를 해결하기 위해 데이터베이스 개념을 도입하였다.
🎈 파일 시스템
데이터를 파일로 관리하기 위해 파일 생성, 삭제, 수정, 검색하는 기능을 제공하는 소프트웨어로, 응용 프로그램마다 필요한 데이터를 별도의 파일로 관리
🎈 파일 시스템의 한계
- 데이터 정의가 응용 프로그램에 내포되어 있음
- 프로그램에서 데이터에 접근하여 조작하는 것 외에 별도의 제어가 없음
파일에 접근하는 방식이 응용 프로그램 내에 표현되므로 응용 프로그램과 데이터 간의 의존 관계가 존재하여 데이터의 구조, 접근 방법이 변경되면 기존 프로그램과 데이터를 함께 변경해야 함
📒 Database의 정의
Database
여러 사람들이 공유하고 사용할 목적으로 통합 관리되는 데이터들의 모임
사용 목적
파일 시스템의 데이터의 종속성, 중복, 무결성 문제 해결
📒 Database의 특징
1) 데이터의 독립성
-
물리적 독립성: 데이터베이스의 사이즈를 늘리거나 데이터 파일을 새롭게 추가하더라도 관련 응용 프로그램 수정 X
↔ 파일 시스템은 응용 프로그램의 기능을 확장하려면 파일 구조 재조직 필요
-
논리적 독립성: 데이터베이스는 논리적인 구조로 다양한 응용 프로그램의 논리적 요구를 만족 가능
↔ 파일 시스템에서는 파일의 구조가 응용 프로그램에 반영되어 있기 때문에 파일의 구조가 바뀌면 영향을 받는 모든 응용 프로그램을 수정해야 함
2) 데이터의 무결성
여러 경로를 통해 잘못된 데이터가 발생하는 경우의 수를 방지하는 기능 ▶ 데이터 유효성 검사
↔ 파일 시스템은 응용 프로그램 별로 제약 조건을 하나하나 처리해야 하기 때문에 무결성을 유지하기 어려움
3) 데이터의 보안
인가된 사용자들만 데이터베이스나 데이터베이스 내의 자원에 접근할 수 있도록 계정 관리 또는 접근 권한을 설정 ▶ 데이터 보안 구현
↔ 파일 시스템은 파일 단위로 검색, 갱신, 실행 등의 권한을 부여할 수 있어 사용자 별 접근 제어가 어려움
4) 데이터의 일관성
연관된 정보를 논리적인 구조로 관리함으로써 어떤 하나의 데이터만 변경했을 경우 발생할 수 있는 데이터의 불일치성 배제
작업 중 일부 데이터만 변경되어 나머지 데이터와 일치하지 않는 경우의 수 배제
↔ 파일 시스템에서는 중복된 데이터를 변경하기 어려워 중복 데이터 중 일부만 변경될 경우 중복 데이터 간 불일치 발생 가능
5) 데이터 중복 최소화
데이터베이스는 데이터를 통합해서 관리함으로써 파일 시스템의 단점 중 하나인 자료의 중복, 데이터의 중복성 문제 해결
↔ 파일 시스템은 응용 프로그램 별 데이터를 파일로 관리하기 때문에 같은 데이터가 여러 파일에 저장되어 데이터 중복 문제가 발생 가능
📒 데이터베이스의 성능
DB 성능 지표: 메모리 용량, 캐시 히트율, 페이지 기대 수명, 초당 체크포인트 페이지 수, 리소스 사용량, 행(Row) 수, 잠금 및 블록, 잠금 대기, 차단, 인덱스, 데이터베이스 파일 I/O 등
데이터베이스 파일 I/O
메모리 I/O vs 디스크 I/O
- 메모리 I/O: 데이터 입출력이 전기적 신호로 이루어지기 때문에 속도가 매우 빠름
- 디스크 I/O: 디스크의 액세스 암(Arm)이 움직이며 헤드를 통해 데이터를 읽고 쓰기 때문에 느림
▶ 메모리는 물리적으로 한정된 자원이므로, 결국 디스크 I/O를 최소화하고 버퍼 캐시 효율을 높이는 것이 데이터베이스 I/O 튜닝의 목표
▶ 디스크 헤더의 위치 이동 없이 얼마나 많은 데이터를 한 번에 기록하느냐
Sequential I/O vs Random I/O
- Sequential Access: 레코드 간 논리적 또는 물리적인 순서를 따라 차례대로 읽어나가는 방식
- Random Access: 레코드 간 논리적 또는 물리적인 순서를 따르지 않고, 한 건을 읽기 위해 한 블록씩 접근하는 방법
▶ I/O 튜닝의 핵심 원리: Sequential Access가 Random Access보다 빠르기 때문에 Sequential Access에 의한 선택 비중을 높이고 Random Access 발생량을 줄임
📚 Index(인덱스)
추가적인 쓰기 작업, 저장 공간을 활용한 데이터베이스 검색 속도 향상을 위한 자료구조
- 테이블의 모든 데이터를 조회하여 검색을 하면 시간이 오래 걸리므로 데이터와 데이터 위치를 포함한 자료구조를 생성하여 빠른 조회 가능
📒 Index 자료구조
DBMS의 인덱스는 항상 정렬된 상태를 유지하기 때문에 원하는 값을 탐색하는 것은 빠르지만 새로운 값을 추가하거나 삭제, 수정하는 경우에는 쿼리 실행 속도가 느려짐
▶ Index는 데이터의 저장 기능을 희생하는 대신 읽기 속도를 높이는 기능
1) B+ Tree 인덱스 알고리즘
컬럼의 값을 변형하지 않고 원래의 값을 이용해 인덱싱 (값의 일부분을 이용)
▶ Hash보다 느리지만 부등호 연산이 가능하다는 점 때문에 일반적으로 사용
2) Hash 인덱스 알고리즘 (해시 테이블)
컬럼의 값으로 해시 값을 계산하여 인덱싱
▶ 동등 연산(=)에 특화되어 부등호(<>) 연산에 문제가 생기기 때문에 사용 X (메모리 기반 데이터베이스에서 사용)
📒 Clustered Index
- 키 값에 대한 테이블의 데이터 행을 정렬하는 인덱스 유형
- 테이블의 데이터를 정렬하여 저장되는 순서 정의
📒 기본 인덱스(Primary Index)와 보조 인덱스(Secondary Index)의 차이점
기본 인덱스
데이터 파일이 키 순으로 정렬되어 있을 때, 데이트 블록당 하나의 엔트리를 가진다. 기본 인덱스는 블록의 가장 첫 번째 레코드 또는 마지막 레코드의 첫 번째 필드 값을 탐색 키 값으로 갖는다.
▶ 각 블럭 당 하나의 엔트리를 가지기 때문에 희소 인덱스이다.
클러스터드 인덱스 (Clustered index): PK가 비슷한 레코드끼리 묶어서 저장
▶ PK에 의해 레코드의 저장 위치가 결정되며 PK가 변경되면 레코드의 물리적인 저장 위치도 변경되어야 함
- 테이블 당 1개씩만 허용
- 물리적으로 행을 재배열
- PK 설정 시 그 컬럼은 자동으로 클러스터드 인덱스가 생성됨
- 테이블 자체가 인덱스임
- 데이터 입력, 수정, 삭제 시 항상 정렬 상태 유지
- 비클러스터드 인덱스보다 검색 속도는 빠르지만 데이터의 입력, 수정, 삭제는 느림
- 30% 이내에서 사용해야 좋은 선택도를 가짐
넌클러스터드 인덱스 (Non-clustered index)
- 테이블당 약 240개의 인덱스 생성 가능
- 인덱스 페이지는 로그 파일에 저장됨
- 레코드의 원본은 정렬되지 않고, 인덱스 페이지만 정렬됨
- 인덱스가 가리키는 것이 데이터의 위치 포인터(RID)이기 때문에 클러스터드 인덱스보다 검색 속도는 더 느리지만 데이터의 입력, 수정, 삭제는 더 빠름
- 인덱스를 생성할 때 데이터 페이지는 그냥 둔 상태에서 별도의 인덱스 페이지를 따로 만들기 때문에 용량을 더 차지
- 3% 이내에서 사용해야 좋은 선택도를 가짐
📒 Composite Index
SELECT 질의문에 따라 인덱스 생성에 영향을 미친다.
📒 Index 성능과 고려해야 할 사항
- Index 사용이 항상 좋은 것은 아니다.
- INSERT, DELETE, UPDATE 쿼리문을 실행할 때 별도의 과정이 추가적으로 발생하기 때문에 성능 손실이 야기됨
- 데이터의 형식에 따라 인덱스의 성능이 저하될 수 있다.
- 데이터 값의 범위가 작을 경우 디스크 I/O가 추가적으로 발생할 수 있기 때문에 비효율적
📚 정규화
📒 갱신 이상
데이터가 중복 저장될 경우 발생할 수 있음
- 삽입 이상 (insertion anomalies): 원하지 않는 자료가 삽입된다거나 삽입하는데 자료가 부족해 삽입되지 않아 발생하는 문제점
- 삭제 이상 (deletion anomalies): 하나의 자료만 삭제하고 싶지만 그 자료가 포함된 튜플 전체가 삭제됨으로 원하지 않는 정보 손실이 발생하는 문제점
- 수정(갱신) 이상 (modification anomalies): 정확하지 않거나 일부의 튜플만 갱신되어 정보가 모호해지거나 일관성이 없어져 정확한 정보 파악이 되지 않는 문제점
📒 정규화란?
관계형 데이터베이스에서 중복을 최소화하기 위해 데이터를 구조화하는 작업
나쁜 릴레이션(테이블)의 속성들을 나누어 좋은 릴레이션으로 작게 분해하는 작업
- 나쁜 릴레이션
- 엔티티를 구성하고 있는 속성 간의 함수적 종속성(Functional Dependency)을 판단
- 각각의 정규형마다 어떠한 함수적 종속성을 만족하는지에 따라 정규형을 정의하여. 그 정규형을 만족하지 못하는 정규형을 나쁜 릴레이션으로 판단
- 함수적 종속성
- 함수적 종속성이란 속성 데이터들의 의미와 속성들 간의 상호 관계로부터 유도되는 제약 조건의 일종
- 하나의 속성 A가 다른 속성 B의 값을 결정한다면 A는 B를 함수적으로 결정한다고 한다.
제1정규형
릴레이션에 속하는 속성의 속성 값이 모두 원자값(Atomic Value)만으로 구성된 정규형
- 복합 애트리뷰트, 다중값 애트리뷰트, 중첩 릴레이션 등 비원자적인 애트리뷰트들을 허용하지 않는 릴레이션 형태
- PK가 아닌 속성들이 기본키에 완전 함수 종속되지 못하고 부분 함수 종속이 되어있을 경우 이상 현상 발생
제2정규형
제1정규형이면서, PK에 속하지 않은 속성 모두가 기본 키에 완전 함수 종속인 정규형
- 이행적 함수 종속성(속성들 간의 종속성이 꼬여있는 경우)이 있을 경우 이상 현상 발생
제3정규형
제2정규형이면서, 이행적 함수 종속성을 제거한 정규형
- PK에 속하지 않은 모든 속성이 PK에 이행적 함수 종속이 아닐 경우
Boyce and Codd 정규형
제3정규형을 강화시킨 개념으로, 비주요 속성이 후보 키의 일부를 분해하는 과정
📒 정규형의 장단점
장점
- 데이터베이스 변경 시 이상 현상 제거
- 데이터베이스 구조 확장 시 재 디자인 최소화
- 정규화된 데이터베이스 구조에서는 새로운 데이터 형의 추가로 인한 확장 시, 그 구조를 변경하지 않아도 되거나 일부만 변경해도 된다.
- 사용자에게 데이터 모델을 더욱 의미있게 제공
- 정규화된 테이블 간의 관계는 현실 세계의 개념들과 관계를 반영한다.
단점
- 릴레이션의 분해로 인해 릴레이션 간의 연산(JOIN 연산)이 많아져 질의에 대한 응답 시간이 증가
▶ 조회하는 SQL 문장에서 JOIN이 많이 발생하여 이로 인한 성능 저하가 나타나는 경우 반정규화 적용 전략이 필요
📒 반정규화 (De-normalization, 비정규화)
정규화된 엔티티, 속성, 관계를 시스템의 성능 향상 및 개발과 운영의 단순화를 위해 중복 통합, 분리 등을 수행하는 데이터 모델링 기법 중 하나
- 디스크 I/O가 많아서 조회 시 성능이 저하되거나
- 테이블끼리의 경로가 너무 멀어 JOIN으로 인한 성능 저하가 예상되거나
- 컬럼을 계산하여 조회할 때 성능이 저하될 것이 예상되는 경우 수행
▶ 일반적으로 조회에 대한 처리 성능이 중요하다고 판단될 때 부분적으로 반정규화 고려
반정규화 대상
1) 자주 사용되는 테이블에 액세스하는 프로세스 수가 가장 많고, 항상 일정한 범위만을 조회하는 경우
2) 테이블에 대량 데이터가 있고 대량의 범위를 자주 처리하고, 성능 상 이슈가 있을 경우
3) 테이블에 지나치게 JOIN을 많이 사용하게 되어 데이터를 조회하는 것이 기술적으로 어려울 경우
주의할 점
- 반정규화의 적용이 과도할 경우 데이터의 무결성이 깨질 우려
- 입력, 수정, 삭제의 질의문에 대한 응답 시간이 늦어질 수 있음
📚 Transaction (트랜잭션)
작업의 완전성을 보장해주는 것
- 논리적인 작업 셋을 모두 완벽하게 처리 or 처리하지 못할 경우에는 원상태로 복구 ▶ 작업의 일부만 적용되는 현상이 발생하지 않게 만들어주는 기능
- 사용자: 작업의 논리적 단위
- 시스템: 데이터들을 접근 또는 변경하는 프로그램의 단위
📒 트랜잭션과 Lock
잠금(lock): 동시성 제어
- 여러 커넥션에서 동시에 동일한 자원(레코드 or 테이블)을 요청할 경우 순서대로 한 시점에서는 하나의 커넥션만 변경할 수 있게 해주는 역할
트랜잭션: 데이터의 정합성을 보장 (데이터의 값이 서로 일치하는 상태)
- 하나의 논리적인 작업 셋 중 쿼리의 개수와는 관계없이 논리적인 작업 셋 자체가 100% 적용되거나 아무것도 적용되지 않아야 함을 보장
📒 트랜잭션의 특성 (ACID)
원자성(Atomicity)
만약 트랜잭션 중 문제가 발생하면 트랜잭션이 수행되지 않아야 하고, 아무런 문제가 발생되지 않았을 때에만 모든 작업이 수행되어야 한다.
일관성(Consistency)
트랜잭션이 완료된 다음의 상태에서도 데이터의 일관성이 보장되어야 한다.
고립성(Isolation)
각각의 트랜잭션은 서로 간섭없이 독립적으로 수행되어야 한다.
지속성(Durability)
트랜잭션이 정상적으로 종료되면 작업의 결과가 영구적으로 데이터베이스에 저장되어야 한다.
📒 트랜잭션의 상태
Active
트랜잭션이 실행, 동작중인 상태
Failed
트랜잭션이 더이상 정상적으로 진행될 수 없는 상태
Partially Committed
트랜잭션의 Commit 이전 sql 문이 수행되고 commit 만 남은 상태
Committed
트랜잭션이 정상적으로 완료된 상태
Aborted
트랜잭션이 취소되고 트랜잭션 실행 이전 데이터로 돌아간 상태
Partially Committed와 Committed의 차이점
Partially Committed: commit 요청을 받은 상태
Committed: commit 요청을 받아 작업을 수행한 뒤 commit이 실행된 상태
📚 교착 상태
두 개 이상의 트랜잭션이 특정 자원(테이블 또는 행)의 잠금(lock)을 획득한 채 다른 트랜잭션이 소유하고 있는 잠금을 요구하면 아무리 기다려도 상황이 바뀌지 않는 상태
📒 교착 상태의 빈도를 낮추는 방법
- 트랜잭션 커밋 빈도 증가
- 정해진 순서로 테이블에 접근
- 읽기 잠금 획득 (SELECT ~ FOR UPDATE)의 사용 지양
- 테이블 단위의 잠금을 획득해 갱신을 직렬화 하면 동시성은 떨어지지만 교착상태 회피 가능
📚 Statement와 PreparedStatement의 차이점
📒 Statement
- 쿼리 문장 분석 ▶ 컴파일 ▶ 실행 의 단계를 쿼리 수행 시마다 반복해야 하기 때문에 매번 컴파일 하는 과정에서 성능상 이슈 발생
- static sql 사용
📒 PrepareStatement
- 쿼리 문장 분석 ▶ 컴파일 ▶ 실행 단계는 처음 한 번만 실행하고, 캐시에 담아 재사용하기 때문에 반복적인 쿼리 수행 시 DB에 적은 부하를 주고 좋은 성능을 보임
- dynamic sql 사용
▶ SQL Injection 등의 문제를 보완해주는 PreparedStatement를 사용하는 것이 옳다.
📚 NoSQL
- 특정 데이터 모델에 대해 특정 목적에 맞추어 구축되는 데이터베이스로, 현대 애플리케이션 구축을 위한 유연한 스키마를 사용 가능
- 관계형 데이터 모델을 지양
- 대량의 분산된 데이터를 저장하고 조회하는데 특화됨
- 스키마 없이 사용 가능하거나 느슨한 스키마를 제공하는 저장소
📒 저장 방식에 따른 NoSQL 분류
Key-Value Model
- 가장 기본적인 형태의 NoSQL로, 하나의 키에 하나의 데이터를 저장하고 조회하는 key-value 구조를 가짐
- 복잡한 조회 연산은 지원하지 않으며 고속 읽기와 쓰기에 최적화
- 예. 사용자의 프로필 정보, 웹 서버 클러스터를 위한 세션 정보, 장바구니 정보, URL 단축 정보
- 하나의 서비스 요청에 다수의 데이터 조회 및 수정 연산이 발생하면 트랜잭션 처리가 불가능하여 데이터 정합성을 보장할 수 없음
Document Model
- Key-Value 모델을 개념적으로 확장한 구조
- 하나의 키에 하나의 구조화된 문서를 저장하고 조회
- 논리적인 데이터 저장과 조회 방법이 관계형 데이터베이스와 유사
- 키는 문서에 대한 ID로 표현
- 문서 ID에 대한 인덱스를 사용하여 O(1) 시간 안에 문서 조회 가능
- 예. 중앙 집중식 로그 저장, 타임라인 저장, 통계 정보 저장 등
Column Model
- 하나의 키에 여러 개의 컬럼 이름과 컬럼 값의 쌍으로 이루어진 데이터 저장, 조회
- 저장의 기본 단위: 컬럼 (컬럼 이름, 컬럼 값, 타임스탬프)
출처