관계형 데이터베이스
관계형 데이터베이스(RDBMS)는 행과 열을 가지는 표 형식 데이터를 저장하는 형태의 데이터베이스를 가리키며 SQL이라는 언어를 써서 조작합니다. 종류로는 MySQL, PostreSQL, Oracle, SQL Server, MSSQL 등이 있습니다.
NoSQL 데이터베이스
NoSQL(Not only SQL)이라는 슬로건에서 생겨난 데이터베이스입니다. SQL을 사용하지 않는 데이터베이스를 말하며 대표적으로 MongoDB와 Redis가 있습니다.
MongoDB는 JSON을 통해 데이터에 접근할 수 있고, Binary JSON(BJSON)로 데이터가 저장되며 와이어드타이거 엔진이 기본 스토리지 엔진으로 장착된 키-값 데이터모델에서 확장된 도큐먼트 기반의 데이터베이스입니다.
Redis는 인메모리 데이터베이스이자 키-값 데이터 모델 기반의 데이터베이스입니다. 기본적인 데이터 타입은 문자열(String)이며 최대 512MB까지 저장할 수 있으며 셋(set), 해쉬(hash) 등을 지원합니다.
pub/sub 기능을 통해 채팅 시스템, 다른 데이터베이스 앞단에 두어 사용하는 캐싱 계층, 단순한 키-값이 필요한 세션 정보 관리, 정렬된 셋(sorted set) 자료 구조를 이용한 실시간 순위표 서비스에 사용합니다.
인덱스(Index)
인덱스(Index)는 데이터를 빠르게 찾을 수 있는 하나의 장치입니다. 테이블 안에 내가 찾고자 하는 데이터를 빠르게 찾을 수 있도록 도와주는 기능을 합니다.
B-Tree
인덱스는 보통 B-Tree라는 자료 구조로 이루어져 있으며 루트 노드, 리프 노드, 루프 노드와 리프 노드 사이에 있는 브랜치 노드로 나뉩니다.

먼저 루트 노드와 리프 노드를 기반으로 설명하자면 E를 찾는다고 하였을 떄 전체 테이블을 탐색하는 것이 아니라 E가 있을 법한 리프 노드로 들어가서 E를 탐색하면 쉽게 찾을 수 있습니다. 이 자료 구조 없이 E를 탐색하고자 하면 A, B, C, D, E 다섯 번을 탐색해야 하지만, 이렇게 노드들로 나누면 두 번만에 리프 노드에서 찾을 수 있습니다.

그림과 같이 트리 탐색은 맨 위 루트 노드붵 탐색이 일어나며 브랜치 노드를 거쳐 리프 노드까지 내려옵니다. '57보다 같거나 클 때까지 <='를 기반으로 처음 루트 노드에서는 39, 83 이후 아래 노드로 내려와 46, 53, 57 등 정렬된 값을 기반으로 탐색하는 것을 볼 수 있습니다. 이렇게 루트 노드부터 시작하여 마지막 리프 노드에 도달해서 57이 가리키는 데이터 포인터를 통해 결과값을 반환하게 됩니다.
인덱스를 사용함으로써 효율적인 이유와 대수확장성
인덱스가 효율적인 이유는 효율적인 단계를 거쳐 모든 요소에 접근할 수 있는 균형 잡힌 트리 구조와 트리 깊이의 대수 확장성때문입니다.
대수확장성이란 트리 깊이가 리프 노드 수에 비해 매우 느리게 성장하는 것을 의미하며 기본적으로 인덱스가 한 깊이씩 증가할 때마다 최대 인덱스 항목의 수는 4배씩 증가합니다.
| 트리 깊이 | 인덱스 항목의 수 |
|---|---|
| 1 | 4 |
| 2 | 16 |
| 3 | 64 |
| 4 | 256 |
| 5 | 1024 |
| 6 | 4096 |
| 7 | 16384 |
| 8 | 65536 |
| 9 | 262144 |
| 10 | 1048576 |
실제 인덱스는 이것보다 더욱 효율적이며 그렇기 떄문에 인덱스가 효율적이라고 볼 수 있습니다.
인덱스를 만드는 방법
인덱스를 만드는 방법은 데이터베이스마다 다르며 MySQL과 MongoDB를 기준으로 설명하겠습니다.
MySQL의 인덱스를 만드는 방법
MySQL의 경우 클러스터형 인덱스와 세컨더리 인덱스가 있으며, 클러스터형 인덱스는 테이블당 하나를 설정할 수 있습니다. primary key 옵션으로 기본키로 만들면 클러스터형 인덱스를 생성할 수 있고 기본키로 만들지 않고 unique not null 옵션을 붙이면 클러스터형 인덱스로 만들 수 있습니다.
create index ~명령어를 기반으로 만들면 세컨터리 인덱스를 만들 수 있으며 하나의 인덱스만 생성하 것이라면 클러스터형 인덱스를 만든는 것이 세컨터리 인덱스를 만드는 것보다 성능이 좋습니다.
세컨터리 인덱스는 보조 인덱스로 여러 개의 필드 값을 기반으로 쿼리를 많이 보낼 때 생성해야 하는 인덱스입니다. 예를 들어 age라는 하나의 필드만으로 쿼리를 보낸다면 클러스터형 인덱스만이 필요하겠지만 age, name, email 등 다양한 필드를 기반으로 쿼리를 보낼 때는 세컨더리 인덱스를 사용해야 한다.
MongoDB의 인덱스를 만드는 방법
MongoDB의 경우 도큐먼트를 만들면 자동으로 ObjectID가 형성되며, 해당 키가 기본키로 설정됩니다. 그리고 세컨더리키도 부가적으로 설정해서 기본키와 세컨더리키를 같이 쓰는 복합 인덱스를 설정할 수 있습니다.
인덱스 최적화 기법
1. 인덱스는 비용입니다.
인덱스를 사용하면 데이터 조회가 빨라지지만, 데이터 삽입과 업데이트 시에는 인덱스도 함께 갱신해야 하므로 성능에 비용이 발생합니다. 또한, 인덱스는 추가적인 저장 공간을 사용하기 때문에 적절한 인덱스를 설계하지 않으면 오히려 성능이 저하될 수 있습니다. 그렇기 때문에 자주 조회하는 컬럼에만 인덱스를 추가하고, 쿼리의 특성을 잘 파악하여 필요한 인덱스만 설정하는 것이 중요합니다. 특히, 테이블이 크고 데이터량이 많을수록 무작정 인덱스를 다 추가하는 것은 비효율적일 수 있습니다.
2. 항상 테스팅을 해야 합니다.
인덱스의 효과는 테이블의 크기, 데이터 분포, 쿼리 패턴 등에 따라 달라지므로, 인덱스 최적화 시에는 항상 테스팅을 거쳐야 합니다. MySQL에서는 EXPLAIN 명령어를 사용해 쿼리 실행 계획을 확인할 수 있습니다.
인덱스를 적용한 후 실행 계획을 확인하여, 쿼리가 인덱스를 잘 활용하고 있는지 확인하고 성능 개선이 필요한 부분을 파악해야 합니다.
MySQL에서 테스팅하는 코드 예시는 다음과 같습니다.
EXPLAIN
SELECT * FROM T1
JOIN T2 ON T1.C1 = T2.C1
이와 같이 EXPLAIN을 사용해 쿼리를 실행한 후, 쿼리 실행 계획을 분석하여 인덱스의 효율성을 평가하고 쿼리 최적화를 진행할 수 있습니다.
3. 복합 인덱스는 같음, 정렬, 범위, 카디널리티 순으로 설정합니다.
MySQL에서 여러 필드를 기준으로 검색하는 경우, 복합 인덱스를 사용하는 것이 효율적입니다. 복합 인덱스를 만들 때는 필드 순서를 신중하게 선택해야 합니다. 일반적으로 '같음' 조건, '정렬' 조건, '범위' 조건, 그리고 '카디널리티'를 고려해 필드 순서를 정합니다.
같음 조건: 특정 값을 비교하는 = 조건이 있는 필드는 가장 먼저 인덱스로 설정하는 것이 좋습니다. 이는 쿼리의 효율성을 높이기 때문입니다.
정렬 조건: 쿼리에서 ORDER BY로 정렬하는 필드가 있다면 두 번째로 인덱스로 설정하는 것이 좋습니다. 정렬에 따라 쿼리 성능에 영향을 줄 수 있습니다.
범위 조건: 여러 값을 포함하는 범위 쿼리 (>, <, BETWEEN 등)를 사용하는 필드는 나중에 인덱스로 설정하는 것이 좋습니다. 범위 조건은 부분적으로만 인덱스를 사용할 수 있으므로 인덱스의 효율성을 제한할 수 있습니다.
카디널리티: 카디널리티는 해당 컬럼의 유니크한 값의 수를 의미합니다. 카디널리티가 높은 필드를 인덱스의 우선순위로 고려하는 것이 좋습니다. 예를 들어 age와 email 컬럼이 있을 때, email이 더 유니크한 값이 많으므로 email을 우선 인덱스로 설정하는 것이 좋습니다.
이러한 최적화 기법을 활용해 쿼리 성능을 높이고, 테이블의 특성에 맞는 인덱스를 설계하여 데이터베이스 성능을 최대한 활용할 수 있습니다.
'🗂️ Database' 카테고리의 다른 글
| [데이터베이스] 조인의 종류와 원리 (2) | 2024.11.09 |
|---|---|
| [데이터베이스] 트랜잭션과 무결성 (1) | 2024.11.03 |
| [데이터베이스] ERD와 정규화 과정 (0) | 2024.11.02 |
| [데이터베이스] 데이터베이스의 기본 (0) | 2024.11.02 |