카테고리 없음

CS 1주차 - Database

오쟝 2024. 10. 14. 21:12
Key란?
키는 검색, 정렬 시 튜플을 구분할 수 있는 기준이 되는 속성

 
1. Candidate Key (후보키)
튜플을 유일하게 식별하기 위해 사용하는 속성들
유일성, 최소성이라는 조건을 만족
* 최소성 : 하나의 키로만 튜플을 찾아냄
 
2. Primary Key (기본키)
후보키 중 선택한 주요 키
Null이나 중복된 값은 될 수 없음
 
3. Alternate Key (대체키 = 보조키)
후보키 중 기본키를 제외한 나머지 키
 
4. Super Key (슈퍼키)
유일성은 만족, 최소성은 불만족
* 학생을 찾을 때, 나이와 생일을 사용해 찾는다면 최소성은 불만족
 
5. Foreign key (외래키)
데이터가 일관될 수 있도록 돕는 역할
보통 두 개 이상의 DB를 연결할 때 사용하는 키
 

JOIN

A 테이블 B 테이블
이름 개수 이름
사과 5 과일 고양이 동물
딸기 8 과일 고슴도치 동물
포도 3 과일 돼지 동물
고양이 2 동물 강아지 동물

 
1. INNER JOIN (교집합)
중복된 값만 보여줌

1 고양이 동물

 
2. LEFT OUTER JOIN
왼쪽 테이블과 오른쪽 테이블 중 중복된 왼쪽 테이블만 보여줌

1 고양이 2 동물

 
3. RIGHT OUTER JOIN
오른쪽 테이블과 왼쪽 테이블 중 중복된 오른쪽 테이블만 보여줌

1 고양이 동물

 
4. FULL OUTER JOIN (합집합)
왼쪽 테이블과 오른쪽 테이블의 모든 데이터를 검색함

1 사과 5  
2 딸기 8  
3 포도 3  
4 고양이 2 동물
5 고슴도치   동물
6 돼지   동물
7 강아지   동물

 
5. CROSS JOIN
왼쪽 테이블과 오른쪽 테이블의 모든 경우의 수 표현
 
A 테이블 튜플 4개
B 테이블 튜플 4개
=> 16개의 경우의 수 표현
 
6. SELF JOIN
자기자신과 자기자신을 조인 = 하나의 테이블을 여러번 복사에서 조인
 

INJECTION이란?

INJECTION은 악의적인 사용자가 보안상의 취약점을 이용해 임의의 SQL문을 주입해 실행되게 하여 데이터 베이스가 정상적으로 작동하지 않도록 하는 행위

공격 방법

1. 논리적 오류

2. 데이터 노출

 

방어 방법

1. input값을 받을 떄, 특수문자 여부 검사하기

2. SQL 서버 오류 발생 시 발생하는 에러 메시지 숨기기 -> 데이터 노출 공격을 막기 위해

3. preparestatement 구문 사용

 

 

SQL VS NoSQL


SQL이란?

관계형 데이터를 저장
  • 정해진 데이터 스키마에 따라서 테이블에 저장 -> 정해진 스키마에 맞지 않는 값은 추가가 불가능
  • 관계를 통해 여러 테이블에 분산
  • 데이터의 중복을 피하기 위해서 관계를 사용

=> 관계를 맺고 있고 자주 변경되는 데이터를 저장하는 경우, 변경될 여지가 없고 정확한 스키마와 데이터가 중요한 경우

 

NoSQL이란?

비관계형 데이터를 저장
  • 다른 구조의 데이터 추가 가능
  • SQL처럼 여러 테이블에 나누어 담지 않고 하나의 컬렉션에 담음
  • 데이터의 중복 위험이 있기 때문에 조인을 자주 사용하지 않고 잘 변경되지 않는 데이터일 시 효율적

=> 정확한 데이터 구조를 알 수 없거나 변경/확장 될 수 있는 경우, 데이터 변경이 자주 없는 경우, 데이터 베이스를 수평적으로 확장해야하는 경우

 

 

장점

SQL NoSQL
스키마 덕분에 데이터가 일관성을 가짐 스키마가 없어 유연하고 언제든 조정 가능
데이터를 중복 없이 딱 한 번만 저장 어플리케이션이 필요로 하는 형식으로 저장해 빠름
  수직/수평 확장이 가능해 어플리케이션의 모든 읽기/쓰기 처리

 

 

단점

SQL NoSQL
데이터 스키마를 사전에 계획하고 알려야 해 덜 유연함 유연성으로 데이터 구조 결정을 미룰 수 있음
관계가 정의되어 있어 복잡한 조인문을 사용해야 할 수 있음 데이터 중복으로 인해 주기적인 업데이트가 필요함
보통 수직적 확장만 가능 데이터 중복으로 인해 수정시 모든 컬렉션에서 수정

 

 

** 수직적 확장? 수평적 확장?

수직적 확장 : 단순히 데이터 베이스 서버의 성능을 향상시키는 것

수평적 확장 :  더 많은 서버가 추가되고 데이터 베이스가 전체적으로 분산

 

 

정규화

데이터의 중복을 줄이고 무결성을 향상시키는 역할 + 테이블 구성을 논리적이고 직관적이게, 확장을 용이하게!

 


 

제 1 정규화

테이블의 컬럼이 원자값을 가지도록 테이블을 분해하는 것
이름
오지은 3반, 4반
추다율 1반, 2반
안민선 2반
배주연 4반

 

이런 테이블이 있을 때

오지은과 추다율은 반이 여러 개이기 때문에 제 1 정규화에 대해서 불만족

제 1 정규화를 진행하게 되면

 

이름
오지은 3반,
오지은 4반
추다율 1반
추다율 2반
안민선 2반
배주연 4반

 

제 2 정규화

제 1 정규화를 진행한 테이블에 대해 기본키의 부분집합이 결정자가 되지 않게 테이블을 관리하는 것

 

 

중복데이터로 인해 학생번호나 강좌이름 단독으로 성적을 알 수 없음

학생번호와 강좌이름을 합친 기본키로만 성적을 알 수 있음

이때 강의실은 강좌이름에 종속되어 있음

이렇게 기본키 중에 특정 컬럼에만 종속된 컬럼이 존재할 경우 제 2 정규화에 맞지 않음

따라서 테이블을 이와 같이 관리하게 되면 학생번호와 강좌이름이 성적을 결정하고, 강좌이름이 강의실을 결정하는 형태가 되게 됨

따라서 특정 컬럼에 종속된 컬럼이 존재하지 않기 때문에 제 2 정규화에 위배되지 않음

 

제 3 정규화

제 2 정규화를 진행한 테이블에 대해 이행적 종속을 없애도록 테이블을 분해하는 것

 

** 이행적 종속 : A -> B이고, B -> C일 때, A -> C가 성립하는 것

이런 테이블이 있을 때 학생번호는 강좌이름을 결정, 강좌이름은 수강료를 결정

만약 학생이 강좌를 바꾸게 되었을 때 이행적 종속에 의해 수강료가 2만원이 되기 때문에 다시 변경하는 번거로움을 해결하기 위해 제 3 정규화 사용

 

이상현상 (Anomaly)

테이블을 설계할 때 잘못 설계하여 데이터를 삽입, 삭제, 수정할 때 생기는 논리적 오류

 

1. 삽입 이상 (Insertion Anomaly)

자료를 삽입할 때 의도치 않은 자료까지 삽입해야만 자료를 테이블에 추가가 가능한 현상

 

2. 갱신 이상 (Update Anomaly)

중복된 데이터 중 일부만 수정되어 데이터 모순이 일어나는 현상

 

3. 삭제 이상 (Deletion Anomaly)

어떤 정보를 삭제하면 의도치 않게 다른 정보까지 삭제 되어버리는 현상

 

:: 이상현상을 해결하기 위해 제 1, 2, 3 정규화를 진행

 

 

인덱스

추가적인 저장 공간을 활용하여 테이블의 검색 속도를 향상시키기 위한 자료구조

 

인덱스를 사용하게 되면 SELECT, UPDATE, DELETE 문의 성능도 향상되는데 이는 레코드를 전체 스캔하지 않기 때문이다!

 

장점

  • 테이블 조회 속도를 줄이고, 성능을 향상시킬 수 있다
  • 시스템의 부하를 줄일 수 있다

 

단점

  • 한 페이지를 동시에 수정할 수 있는 병행성이 줄어든다
  • 인덱스된 필드의 데이터를 업데이트하거나 새로운 레코드를 추가할 시 성능이 떨어진다
  • 데이터가 자주 변경되는 경우 인덱스를 재작성 해야하기 때문에 성능이 떨어진다

 

인덱스를 사용하면 좋은 경우 -> 평소에는 레코드를 전체 스캔해서 데이터를 찾는 경우

  • WHERE 절이 자주 사용되는 column
  • 외래키가 사용되는 column
  • JOIN에 자주 사용되는 column

 

인덱스를 사용하면 좋지 않은 경우

  • 데이터의 중복이 많은 경우
  • DML이 자주 일어나는 column -> 데이터가 새로 추가, 수정 또는 삭제 되면서 인덱스를 재작성 해야하기 때문에 성능 저하

 

** DML : 데이터 조작어 (SELECT, INSERT, DELETE, UPDATE 등 데이터를 어떻게 활용할 지 정해주는 명령어)

 

인덱스의 자료구조

1. 해시 테이블 - 키를 해싱하여 저장하는 방식

만약 등호(==) 연산이 자주 사용될 경우 인덱스의 자료구조로 적합하지만, 부등호 연산이 자주 사용되는 경우에는 적합하지 않음

: 키 값이 하나라도 틀려지면 새로운 키를 만들어 내기 때문에

 

2. B+Tree - 값은 리프노드에만 저장되어 있는 구조

리프노드끼리는 연결 리스트로 연결되어 있어 부등호 연산에 유리

 

3. B-Tree - 이진 트리와 유사하지만 자식의 수가 N개

 

자료구조에 대한 내용은 다음 포스트에서 정리!

 

트랜잭션

데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위

 

특징

  • 원자성 : 트랜잭션이 데이터베이스 전체에 반영되거나, 아예 반영되지 말아야 한다
  • 일관성 : 트랜잭션의 작업 결과는 항상 일정해야 한다
  • 독립성 : 둘 이상의 트랜잭션이 동시에 실행될 때, 각 트랜잭션은 서로의 연산에 영향을 주지 말아야 한다
  • 지속성 : 트랜잭션이 성공적으로 마무리 되었을 때, 이 결과는 영구적으로 반영되어야 한다

- commit : 트랜잭션 하나가 성공적으로 끝났을 때 이를 알리기 위해 사용하는 연산

- rollback : 트랜잭션의 처리가 비정상적으로 끝나 원자성이 깨진 경우

 

트랜잭션 관리를 위한 DBMS 전략!

** DBMS : 데이터베이스를 관리하고 운영하는 소프트웨어

 

1. UNDO - 어떠한 이유로 트랜잭션이 정상적으로 종료될 수 없을 때, 트랜잭션이 변경한 페이지를 원상복구하는 작업

 수정된 페이지들이 버퍼 교체 알고리즘에 의해 디스크에 출력될 수도 있음 -> 버퍼 교체는 트랜잭션과 무관하게 버퍼 상태에 따라 결정

  • STEAL : 수정된 페이지를 언제든지 디스크에 쓸 수 있는 정책 -> 작업 도중 틀린 작업이 있어도 계속 저장
  • ¬STEAL : 수정된 페이지를 최소한 트랜잭션 종료시점까지는 버퍼에 유지하는 정책 -> 작업이 완료된 후에 저장

 

2. REDO - commit한 트랜잭션의 수정을 재반영하는 복구 작업

  • FORCE: 수정했던 모든 페이지를 트랜잭션 커밋 시점에 디스크에 반영하는 정책 -> 작업이 끝나자마자 바로 저장
  • ¬FORCE: 수정했던 페이지를 트랜잭션 커밋 시점에 디스크에 반영하지 않는 정책 -> 작업이 끝나도 시간이 지난 후 저장

 

DBMS 구조

1. 외부 단계 - 사용자와 데이터베이스 연결하는 단계

사용자가 데이터에 접근할 때 사용하는 인터페이스

 

  • 사용자가 직접적으로 다루는 SQL 질의나 API를 통해 DB에 접근하는 영역
  • 실제 데이터가 저장된 방식(내부 구조)은 전혀 신경 쓰지 않게 추상화된 단계

 

 

2. 개념 단계 - 데이터 전체를 관리하고 설계하는 단계

데이터베이스 전체의 논리적 설계 관리

테이블, 열, 데이터 타입, 제약조건 등을 설계

 

  • ERD로 테이블을 설계하거나, 테이블 간 관계를 정의하는 단계
  • 데이터 모델링에서 이 단계가 매우 중요하며, 실제 물리적인 저장 방식과는 독립적

 

 

3. 내부 단계 - 데이터를 실제로 저장하고 관리하는 단계

데이터를 실제로 디스크에 저장하고 관리하는 단계

데이터 저장 구조, 페이지 관리, 캐싱, 버퍼 관리 등 성능 최적화에 필요한 기술이 여기에 포함

데이터가 어떻게 저장되고, 어떻게 읽어올지 결정하는 단계로 성능에 가장 중요한 역할

 

  • 물리적 저장 방식이나 인덱스 설계, 파티셔닝, 샤딩 등 DB 최적화 작업

 

트랜잭션 격리 수준

여러 트랜잭션이 동시에 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 수정중인 데이터를 볼 수 있는 허용 여부 결정

 

READ UNCOMMIT - SELECT문이 실행되는 동안 해당 데이터에 Shared Lock이 걸리지 않음

트랜잭션 A, B가 실행될 때 트랜잭션 B가 commit되기 이전 update된 데이터를 읽을 수 있음

다른 사용자는 트랜잭션이 아직 처리중이거나 commit되지 않아도 읽는 것이 허용됨

 

READ COMMIT - SELECT문이 실행되는 동안 해당 데이터에 Shared Lock이 걸림

트랜잭션 A에서 update된 내용을 다른 트랜잭션이 바로 읽을 수는 없음

트랜잭션 A가 커밋되었지만 트랜잭션 B가 아직 커밋되지 않은 경우, 다시 조회하면 반영이 됨

다른 사용자는 트랜잭션이 아직 처리중이면 대기해야함

 

REPETABLE READ - 트랜잭션이 완료되기 전까지 SELECT문이 사용하는 모든 데이터에 Shared Lock이 걸림

트랜잭션이 범위 내에서 조회한 데이터에 대해서는 일관성 유지

다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대해서 수정 불가능 

 

SERIALIZABLE - 트랜잭션이 완료되기 전까지 SELECT문이 사용하는 모든 데이터에 Shared Lock이 걸림

다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대해서 수정 및 입력 불가능

 

동시성이 증가하면 무결성이 감소하고, 동시성이 감소하면 무결성이 증가하기 때문에 선택시 고려해야함

 

낮은 단계의 격리 단계를 사용하게 되면 생기는 문제

 

Dirty Read - 커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있게 하면 발생하는 현상 (READ UNCOMMIT LEVEL)

Non-Repeatable Read - 한 트랜잭션에서 같은 쿼리를 두 번 이상 반복 할 때, 다른 트랜잭션이 사이에서 값을 수정 또는 삭제하면 쿼리의 결과가 다르게 나오는 현상 (READ COMMIT LEVEL)

Phantom Read - 한 트랜잭션이 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫번째 쿼리에서 읽은 값이 두 번째 쿼리에서도 나오는 현상 (REPEATABLE READ LEVEL)

 

 

저장 프로시저

쿼리문의 집합으로, 어떤 동작을 여러 쿼리를 통해 일괄적으로 처리할 때 사용

 

장점

- 성능 및 캐시 : 최초 실행 시 캐시에 저장이 되며, 이후 사용시 캐시에서 받아오기 때문에 성능이 향상

- 유지보수 : 작업 변경 시 프로시저 내부만 수정을 하면 됨

- 보안 강화 : 프로시저 내에서 참조중인 테이블의 접근을 막을 수 있음

- 네트워크 부하 감소 : SQL문이 아닌 프로시저에 매개변수만 담아서 전달하기 때문에 트래픽 감소

 

프로시저 예시

SELECT * FROM USER_TABLE WHERE NAME = "오지은"

 

이런 SQL 구문이 있다고 가정했을 때, 이를 프로시저로 만들면

CREATE PROC SELECT_BY_NAME @Name VARCHAR(10)
AS SELECT * FROM USER_TABLE WHERE NAME = @Name

 

형식이 되게 됨

 

이후 프로시저를 사용하게 되면

EXEC SELECT_BY_NAME '오지은'

과 같이 사용할 수 있음

 

 

Redis

key, value 구조의 비관계형 데이터를 저장하고 관리하기 위한 DBMS

 

보통 데이터베이스는 SSD에 저장해서 사용하지만, redis는 RAM에 저장하여 사용하기 때문에 속도가 매우 빠름

SSD 저장의 장점은 물리 디스크에 직접 저장하기 때문에 서버에 문제가 생겨 다운되더라도 데이터 손실이 없지만 사용자가 증가하게 되면 느려질 수 있음

RAM 저장의 장점은 디스크 스캐닝이 없어 매우 빠르지만 서버에 문제가 생겨 다운되게 되면 데이터가 날라감

 

그래서!

백업 과정

 

- snapshot : 특정 시점을 설정하고 디스크에 백업

- AOF : 쿼리들을 저장해두고 서버가 다운되면 재실행해서 다시 만들어 놓는 것

 

redis value에 들어갈 수 있는 값

- String

- Set (String의 집합)

- Sorted Set

- Hash

- List 

 

** 캐시 : 자주 사용하는 데이터를 미리 복사해두는 임시 장소