저는 최근에 면접 스터디의 리더로서 면접 스터디를 이끌고 있는데, CS 면접 스터디 준비를 위해 공부했던 내용들을 올려보려고 합니다. 이 게시글을 시리즈 물로 아무래도 2편 정도 더 업로드 될 것 같은데 최대한 많은 내용을 담기 위해 노력해 보겠습니다.
CS 면접 스터디 - 데이터베이스 편
핵심 개념
1) Key (키)
- 정렬이나 검색시 레코드를 구분할 수 있는 기준이 되는 속성
a. 후보키: 각 레코드를 구분할 수 있는 "최소한의" 속성들의 집합, 유일성과 최소성을 만족
만약 '이름'과 '주민번호' 모두 행을 구분할 수 있다면 후보키가 된다.
하지만, (이름, 주민번호)는 이름 혹은 주민번호 만으로 행을 구분할 수 있기 때문에 최소성을 만족하지 못한다. 따라서 후보키가 될 수 없다. (이름, 주민번호)는 수퍼키에 속한다.
b. 기본키: 후보키 중 선택한 메인키. NULL값을 허용하지 않고, 중복을 허용하지 않는다.
기본키로 적절한 것은 값이 자주 변경되지 않으면서 단순한 속성이다.
c. 대체키: 후보키 중 기본키를 제외한 나머지 키
d. 수퍼키: 유일성은 만족하지만, 최소성은 만족하지 않는 키
e. 외래키: 다른 릴레이션의 기본키를 참조
2) Join (조인)
- 두 개 이상의 테이블을 연결해 테이블을 검색하는 방법
- 서로 컬럼을 공유하고 있으면 조인이 가능함
a. Inner Join: 교집합
b. Left Outer Join: 기준이 되는 테이블을 기준으로 다른 테이블과 겹치는 데이터를 보여준다.
c. Right Outer Join: Left Outer Join과 기준이 되는 테이블이 반대이다.
d. Full Outer Join: 합집합
e. Cross Join: 두 테이블의 데이터를 합치는 모든 경우의 수를 보여줌
f. Self Join: 자기 자신과 데이터를 조인함
3) SQL Injection
- 입력받은 데이터를 그대로 쿼리문에 삽입하게 되면 해커의 악의적인 SQL 쿼리가 실행될 수 있음
- 또는 에러 메시지를 유발시켜 데이터베이스 구조를 유추하여 해킹에 사용하기도 함
- 이를 예방하기 위해서는 다음과 같은 방법이 있음
a. 특수문자 검사
b. DB 관련 에러메시지를 직접 노출 X
c. 모든 사용자 입력 데이터는 문자열 혹은 파라미터 형태로만 쿼리문에 삽입
JDBC API에서는 PreparedStatement가 있고, MyBatis에서는 #{}로 삽입하는 것. MyBatis에서 ${} 형태로 삽입하면 입력 받은 값이 쿼리문 그 자체로 인식되기도 함
4) SQL vs NoSQL
a. SQL
- 데이터는 스키마에 따라 저장, 구조 변경이 어렵고 확장이 제한적임 (수직적 확장만 가능)
- 데이터가 관계를 통해 여러 테이블로 표현됨 (중복이 없음)
- 장점
데이터 무결성 보장
관계를 통해 데이터를 중복없이 저장
- 단점
덜 유연함
관계로 인해 복잡한 조인 발생
대체적으로 수평적 확장만 가능
- 관계가 있는 데이터가 자주 변경되는 경우, SQL을 선택
b. NoSQL
- 데이터 구조가 정해진 것이 없음
- 하나의 레코드는 문서(Document)로 표현
- 관련 데이터들은 하나의 컬렉션(Collection)에 담김, 조인이 없고, 데이터가 중복해서 담길 수 있음
- 장점
데이터 구조 변경에 자유롭기 때문에 비정형 데이터를 저장 가능
조인이 없어서 데이터 읽는 속도가 빠름
수직 수평 확장 모두 가능
- 단점
데이터 중복 발생
데이터가 수정될 경우 중복으로 여러 컬렉션에 담긴 데이터들 모두 수정이 필요함
- 데이터 구조를 명확하게 정의하기 어렵거나 데이터 변경은 없고 읽기 연산이 많은 경우, 그리고 수평적 확장이 필요한 경우 NoSQL을 선택
5) 정규화
a. 제 1정규화: 컬럼이 하나의 값만 갖도록 분리
b. 제 2정규화: 모든 컬림이 완전 함수적 종속을 만족, 기본키를 제외한 속성은 기본키에만 종속적이어야 함.
기본키가 (A, B)일 때, (A) 혹은 (B) 만으로 구분될 수 있는 레코드가 존재하면 안됨.
(A, B) -> C 이고, A -> D라면 A, B, C로 구성된 테이블과 A, D로만 구성된 테이블로 분리됨
c. 제 3정규화: 제 2정규화가 끝난 테이블에서 이형적 종속을 없앰
이형적 종속: A -> B 일 때, B -> C이면, A -> C를 만족하는 경우
(A, B) -> C를 만족하고, C -> D를 만족한다면 A, B, C로 구성된 테이블과 C, D로 구성된 테이블로 분리됨
그림 없이 설명을 했는데, 완벽하게 이해하기 위해서는 그림을 그려볼 것.
6) 이상
학번 | 이름 | 강의코드 | 강의명 | 전화번호 |
1012 | 김00 | L1 | DB | 010-1234-5678 |
1012 | 김00 | L2 | PS | 010-1234-5678 |
a. 삽입 이상
- 강의를 수강하지 않는 학생을 추가하는 경우, 강의 코드와 강의 명에는 NULL 값이 들어가야 함.
- 의도하지 않는 데이터까지 삽입해야만 하는 경우
b. 갱신 이상
- 'L1' 과목 코드를 갖는 학생 김00의 전화번호를 수정하면, 똑같은 김00이지만 서로 다른 전화번호를 갖게 됨.
- 중복된 데이터의 일부만 수정되어 데이터 모순이 발생하는 경우
c. 삭제 이상
- DB 과목을 제거하면 김00 학생 정보도 사라짐.
- 의도하지 않는 정보도 삭제되는 경우
7. 트랜잭션
- 데이터베이스의 상태를 변경시키는 작업의 단위
- ACID 만족
a. 원자성: All or Nothing
b. 일관성: 트랜잭션이 끝나더라도 데이터베이스는 미리 정의된 규칙을 계속해서 만족
c. 독립성: 각 트랜잭션은 다른 트랜잭션에 영향을 끼칠 수 없음
d. 지속성: 트랜잭션의 결과는 영구적으로 반영되어야 함
8. 트랜잭션 격리성
- 관련 게시글은 내 블로그에 조금 더 자세히 정리된 내용이 있다.
https://se-dobby.tistory.com/80
트랜잭션과 격리성 그리고 낙관적 락과 비관적락에 대한 얘기
게시글 서식을 변경했다!! 그리고 "습니다"체를 섞지 않고, 논문처럼 "다"로 끝내는 식으로 게시글들을 통일해서 작성할 것이다. 저번 분산락 설명에서는 비관적 락에 대해서 다루고 있었는데,
se-dobby.tistory.com
- 너무 엄격하면 성능 하락, 너무 풀어주면 데이터 모순 발생
a. Read Uncommitted: 커밋되지 않은 데이터를 읽을 수 있음, Dirty Read, Non-Repeatable Read, Phantom Read 발생
b. Read Committed: 커밋된 데이터만 읽을 수 있음. Select에 의해 특정 데이터에 Shared Lock이 걸리지만 갭락이 걸리지는 않음. 따라서 Non-Repeatable Read, Phantom Read가 발생할 수 있음
c. Repeatable Read: 현재 트랜잭션을 기준으로 자신보다 이전 버전의 데이터들을 읽음. Select에 의해 조회되는 데이터들의 범위에 Shared Lock이 걸림.
d. Serializable: 가장 엄격한 수준의 격리성 수준. 트랜잭션이 완료될 때까지 모든 데이터들에 대해 베타락이 걸림
9. 프로시져
- 여러 SQL을 한번의 요청으로 실행시키고 싶을 때, 프로시져 작성
- 함수 호출하듯이 인자 값만 변경해가며 쉽게 원하는 결과를 획득할 수 있음
10. 인덱스
- 테이블의 검색속도를 향상시키기 위한 자료구조
- 레코드를 풀 스캔하지 않고 B+Tree로 구성된 구조에서 index를 검색하여 속도를 향상시킴
- 테이블은 FRM(구조), MYD(실제 데이터), MYI(인덱스 정보)로 구성됨.
- 따라서 인덱스를 생성하게 되면 테이블 파일인 .mdb의 용량이 증가함
- 인덱스된 영역에서 데이터의 변경, 추가, 삭제 시 성능 하락 -> index도 같이 업데이트해야 하기 때문
- where 절, 외래키, join에서 자주 사용되는 컬럼에 사용하면 좋음
- B-Tree: 탐색이 O(log N), 모든 노드에 값이 저장되며 동시에 포인터 역할도 수행
- B+Tree: 값은 리프노드에만 저장, 리프 노드들끼리는 연결리스트로 연결됨 -> 부등 부호 연산에 효과적임, 나머지 노드들은 포인터 역할만 수행
- Hash Table: 해시 함수 이용, 탐색, 삽입, 삭제에 O(1), 해시 충돌이 일어나면 O(N)이 되기도 함. 부등부호 연산에 사용이 어렵기 때문에 실 시스템에서는 잘 활용하지 않음
- B-Tree의 경우 B+Tree에 비해 메모리 효율이 좋고, 생성, 수정, 삭제 연산에 좀 더 좋은 성능을 보인다.
- B+Tree의 경우 단말노드에만 값이 저장되기 때문에 메모리가 많이 필요하고, 생성, 수정, 삭제 시 리프 노드들 사이의 연결 리스트도 같이 관리해야 하기 때문에 복잡하다.
주고 받은 질문들
- 대체로 대답을 잘했던 질문을 제외하고 조금 버벅였던 질문들은 다음과 같다.
1) 이진 트리가 편향되었을 때, 이를 해결하는 자료 구조
- AVL Tree: 루트 노드를 기준으로 왼쪽 서브 트리의 높이와 오른쪽 서브 트리의 높이가 1 이상 차이나는 경우, Rotation을 통해 편향을 해결
- Red-Black Tree: 자신만의 규칙을 지키도록 되어 있음. Reconstructing과 Recoloring을 통해 편향을 해결. 자세한 알고리즘은 기술하지 않음.
2) 중첩 루프 조인이 무엇인지
- 조인을 할 때, Table A의 특정 행과 조건을 만족하는 Table B의 모든 행을 비교하는 것
- 대규모 데이터 셋에서는 성능 하락 발생
- 기본적으로 조인을 쓰면 중첩 루프 조인 형태로 처리됨
3) 쿼리를 실행하는 과정 (DBMS에서 어떻게 처리되는지)
- 파싱 (Parsing): SQL 파서 모듈에서 문법의 오류나 올바른 데이터 구조를 띄는지 확인
- 최적화 (Optimization): 쿼리 최적화 및 실행 계획 결정, 실행 계획을 결정하는 방식에는 CBO (비용 기반)과 RBO (규칙 기반)이 존재. 기본적으로 MySQL에서는 CBO 사용.
- 결과 반환 (Result retrieval): 스토리지 엔진에 레코드를 읽어오도록 요청하고, MySQL 엔진에서는 스토리지 엔진으로부터 받은 레코드를 조인하거나 정렬하는 작업 후 사용자에게 결과를 반환
4) 덤프파일과 로그 파일의 차이
- 로그 파일: 변경 이력 (트랜잭션 기록)을 저장하는 파일
- 덤프 파일: DB의 전체 데이터와 구조가 저장된 파일
- 로그 파일을 사용하게 되면 트랜잭션 단위로 복구가 가능함. 그렇기 때문에 트랜잭션을 재적용해야 하는 문제로 복구 건수가 많아지면 오래 걸림. 그리고 용량 문제로 로그는 일정 범위만 저장될 수 있기 때문에 너무 과거의 시점으로는 돌아갈 수 없음. 마지막으로 로그에는 변경만 기록되기 때문에 특정 시점에서의 데이터를 알 수 없음
- 이를 보완하기 위해 덤프를 생성함. 덤프 파일은 특정 시점에서의 DB 스냅샷이기 때문에 기준이 될 수 있음
5) 교착 상태의 원인 네 가지
- 상호 배제: 매 순간 하나의 프로세스만이 자원을 사용할 수 있음
- 보유 대기: 자원을 가진 프로세스가 다른 자원을 기다릴 때, 보유하고 있는 자원을 놓지 않고 계속 가짐
- 비선점: 프로세스는 OS에 의해 강제로 자원을 빼앗기지 않음
- 순환대기: 자원을 기다리는 프로세스 간에 사이클 형성
- OS에서 얘기하는 것과 동일함
6) Redis와 RDB를 같이 사용할 때 어떻게 데이터를 저장할지?
- Redis는 휘발성이며, 용량이 한정적이기 때문에 영구적으로 저장될 목적의 데이터를 저장하기 보다는 일시적으로 사용할 데이터들을 저장하는 것이 효과적이라고 생각. 캐시나 Session 정보 같은 것이 될 수 있음. 또, 대규모 요청이 발생하는 시스템에서 락과 같은 권한 관리에 좋음 (싱글 스레드이면서 I/O가 빠르기 때문에). 실제로 티켓팅 프로그램에서 좌석 결제 전에 누가 좌석을 선점하게 되면 해당 좌석에 대한 락을 관리할 때 사용하는 것으로 알고 있음
- RDB: 여기서는 RDB라기 보다는 비교대상으로는 DB가 맞는 것 같음. 영구적으로 저장할 데이터들을 저장하게 됨. 이때, 데이터의 특성에 따라 RDB나 NoSQL을 사용하게 될 것. 만약 읽기 작업이 많고 쓰기 작업이 적다면 CQRS 패턴과 같이 읽기 전용 디비와 쓰기 전용 디비를 분리해서 사용하는 등 적절한 패턴 역시 고민하게 될 것.
처음이 어려웠는데 한번 해보니까 얘기를 주고받는 것이 좋은 것 같다. 특히 내 생각을 많이 얘기하는 습관을 기르면서 내 머릿속에 있는 내용들을 잘 끄집어 낼 수 있는 좋은 기회가 되었으면 좋겠다.
추천글
https://github.com/devSquad-study/2023-CS-Study
GitHub - devSquad-study/2023-CS-Study: 신입 개발자 면접 대비 CS 스터디 👨🏻💻👩🏻💻 🔥
신입 개발자 면접 대비 CS 스터디 👨🏻💻👩🏻💻 🔥. Contribute to devSquad-study/2023-CS-Study development by creating an account on GitHub.
github.com
'취준' 카테고리의 다른 글
비트망고 Backend Programmer (신입 정규직) 채용 후기 (1) | 2025.05.13 |
---|---|
CS 면접 스터디 - 네트워크, 알고리즘 편 (4) | 2025.05.11 |
롯데이노베이트 2025년 3월 채용 K-7 IS팀 Software 직무 채용 후기 (1) | 2025.04.22 |
코스콤 25년 신입직원 채용 - IT 서류, AI 인적성, 코테, 그리고 1차 면접 후기 (1) | 2025.04.05 |
Spring 관련 면접 질문 준비 2 (2) | 2025.03.18 |