Table of Contents
백엔드를 위한 데이터베이스
- 백엔드에서 데이터베이스를 신경쓰게 되는 순간은 크게 다음과 같다
- 데이터베이스 종류
- 쿼리 성능
- 마이그레이션
- 보안
데이터베이스 선택
RDBMS
- 데이터 구조가 일관된 경우
- 저장된 데이터가 분석에 많이 활용되어야 하는 경우
NoSQL
- 데이터 모델링이 아직 안되거나, 아니면 데이터 구조의 변경이 잦아 schema-less를 선호하는 경우
- 데이터 볼륨이 예측되지 않아 확장성이 높아야 하는 경우
Elasticsearch
- 뛰어난 검색엔진을 필요로 하는 경우
RDBMS의 수직 확장은 마이그레이션을 통해 가능하다
RDBMS의 수평 확장은 가능하지만, 수평 확장을 고려해 설계하면 성능이 많이 떨어지게 되고, 다시 축소하는게 거의 불가능하다
쿼리 성능
- 백엔드에서 핵심은 쿼리 성능을 높이는 것이다
- 쿼리 성능을 높일 수 있는 요소에는 여러 가지가 있다
- 데이터베이스 모델링, 인덱스, SQL 쿼리문, 서버 설정 등
- 하지만, 모든 요소를 쿼리 성능을 높이는 데만 초점을 맞출 수는 없다
- 어떤 경우에는 트랜잭션 처리를 요구하기 때문에 쿼리 성능을 감수해야 하는 경우도 있고,
- 어떤 경우에는 읽기 보다 쓰기 성능이 더 중요한 경우도 있다
- 그리고 단순히 서버에 사용할 수 있는 비용도 한계가 있다
모니터링
- 쿼리 성능을 개선하는 방법에는 여러 가지가 있지만, 일단 어떤 쿼리가 자주 사용되고, 어떤 쿼리가 느린지 파악하기 위해서는 모니터링을 해야 한다
쿼리 분석
- 최적화가 필요한 쿼리가 선택됐다면 이제 해당 쿼리가 어떻게 실행되고 있는지 쿼리의 실행 계획을 분석을 해야 한다
인덱스
- 보통 쿼리의 성능 개선은 인덱스를 추가하는 것만으로도 쉽게 이루어진다
- 쿼리가 사용하는 테이블이 읽기 작업의 비율이 높다면 인덱스를 추가하면 좋다
- (인덱스는 정렬되어 있어야 되기 때문에, 쓰기 작업의 성능은 떨어트린다)
- 인덱스 설계는 쿼리문의
WHERE
,JOIN
,ORDER BY
문에 어떤 컬럼이 사용되고 있는지를 통해 결정된다
트랜잭션
- 쿼리의 성능을 높이기 위해서는, 동시에 여러 쿼리 요청을 처리할 수 있어야 한다
- 이 때 가장 중요한 것이 바로 레코드 잠금의 최소화이다
- 그리고 레코드 잠금의 최소화를 방해하는 것이 바로 트랜잭션이 포함된 쿼리다
- (트랜잭션은 잠금의 범위를 늘리고, 인덱스는 잠금의 범위를 줄인다. 그래서 트랜잭션은 쿼리 성능을 떨어트리고, 인덱스는 쿼리 성능을 높이는 것이다)
- 불필요한 트랜잭션은 없애고, 트랜잭션 작업이 필요하다면 트랜잭션 단위를 최소화 하는 것이 좋다
쿼리문
- 그래도 성능에 아쉬움이 있다면, 이제 쿼리문을 직접 건드려야 할 때이다
SELECT
절에 와일드카드(*
)를 없애고 꼭 필요한 컬럼만 포함시킨다WHERE
절에%
를 맨 앞에 쓰지 말고, 함수를 쓰지 말고,BETWEEN
,IN
,<
,>
보다는EXISTS
쓴다JOIN
절의 방법, 순서 등을 잘 선택한다- Subquery, CTE 등을 쓸 수도 있다
서버 튜닝
- 백엔드 개발자도 간단한 서버 튜닝을 할 줄 아는 것이 좋다
- 메모리, 커넥션, 스토리지 엔진의 종류 등 고려해볼만한 요소가 몇 가지 있다
비정규화
- 어떤 두 테이블이 높은 비율로 같이 사용되고, 읽기 비율이 높은 경우에는 두 테이블을 하나로 합치는 비정규화 과정을 통해 쿼리의 성능을 높일 수 있다
- 비정규화는 마이그레이션 작업을 요구하고, 전체 시스템에 꽤나 큰 변화를 일으키기 때문에 신중하게 하는 것이 좋다