섹션 3. HTTP 기본 수강 완료!!
HyperText Transfer Protocol
HTML, TEXT, IMAGE, 음성, 영상, 파일 등 거의 모든 형태의 데이터를 전송 가능.
HTTP 1.1, 2버전은 TCP 기반
HTTP 3버전은 UDP 기반
클라이언트-서버 구조
클라이언트는 서버에 요청(Request)을 보내고 응답(Response)을 기다린다.
서버가 요청에 대한 결과를 만들어서 응답한다.
무상태 프로토콜(Stateless), 비연결성
Stateless: 서버가 클라이언트의 상태를 보존하지 않는다.
장점: 서버 확장성이 높음. (갑자기 클라이언트 요청이 증가해도 서버를 대거 투입할 수 있음.)
단점: 클라이언트가 데이터를 추가로 전송해야 함.
Connectionless: 클라이언트가 요청을 보내고 서버로부터 응답을 받으면 연결을 종료함으로써 서버 자원을 매우 효율적으로 사용할 수 있다.
HTTP 메시지
⬇️ HTTP 메시지 구조
start-line 시작 라인
(요청 메시지 / 응답 메시지)
header 헤더(HTTP 전송에 필요한 모든 부가정보)
empty line 공백 라인(CRLF)
message body(실제 전송할 데이터)
+) 22. 07. 12. 추가 완.
색인 또는 목록이라는 의미이며, 데이터를 기록할 경우 그 데이터의 이름, 데이터의 크기 등 속성과 기록장소 등을 표로 표시한 것. 즉, 참조용의 데이터를 인덱스라 하고 있다. - 정보통신용어사전
데이터베이스에서 인덱스를 사용하는 이유는 검색을 빨리하기 위해서다.
예를 들어, 아래와 같이 db_book이라는 테이블이 있을 때 Transcation 부분만 찾고 싶다 하자.
page | title |
---|---|
1 | Intro |
2 | Intro |
... | ... |
512 | SQL |
513 | SQL |
... | ... |
5545 | Transaction |
5546 | Transaction |
5547 | Transaction |
... | ... |
5700 | Transaction |
5701 | Transaction |
5702 | Concurrency Control |
... | ... |
9999 | Outro |
10000 | Outro |
SELECT page FROM db_book WHERE title = ‘Transaction’
위와 같이 검색할 경우 DB는 10000page까지 Full Scan을 하게 된다.
우리가 필요한 건 Transaction 파트가 시작되는 5545page뿐인데 말이다.
데이터를 풀 스캔 할 경우 시간도 용량도 많이 잡아먹을 것이다.
그래서 이를 해결하기 위해 나온 것이 인덱스다.
title | page |
---|---|
Concurrency Control | 5702 |
Intro | 1 |
SQL | 512 |
Outro | 9999 |
Transaction | 5545 |
위와 같이 index_title 테이블이 있다면 만 번이나 풀 스캔할 필요 없이 다섯 번만 스캔해 주면 된다.
즉, 인덱스를 이용하면 데이터들이 정렬되어 있기 때문에 조건에 맞는 데이터를 빠르게 찾을 수 있다는 뜻이다.
➡️ 테이블의 특정 컬럼에 인덱스를 생성하면, 해당 컬럼의 데이터를 정렬한 후 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다. 컬럼의 값과 물리적 주소를 (key, value)의 한 쌍으로 저장하는 방식이다.
인덱스는 WHERE 절에서 효과가 있다.
WHERE 절을 사용하지 않고 인덱스가 걸린 컬럼을 조회하는 것은 성능 향상에 아무런 영향을 주지 않는다.
또한, 인덱스는 INSERT, UPDATE, DELETE 작업이 자주 발생하지 않는 컬럼, ORDER BY, JOIN 등이 자주 사용되는 컬럼, 데이터의 중복도가 낮은 컬럼에서 효과적이다.
그렇다고 인덱스가 무조건 좋은 건 아니다. 많이 설정한다고 해서 좋은 것도 아니다.
인덱스는 DB의 메모리를 사용해 테이블 형태로 저장된다. 따라서 인덱스의 개수와 저장 공간은 비례한다. 많으면 많을수록 추가 저장 공간이 필요하게 될 것이다.
그리고 인덱스를 항상 정렬된 상태로 유지해야 하기 때문에 인덱스가 적용된 컬럼에 INSERT, UPDATE, DELETE 작업을 수행하면 다음과 같은 추가 작업이 필요하다.
다만 UPDATE, DELETE는 WHERE 절에 잘 설정된 인덱스로 조건을 붙여주면 조회 시 성능은 크게 저하되지 않는다. 하지만 성능이 좋다는 소리는 아니다.
INSERT의 경우 새로운 데이터를 추가하면 기존 인덱스 페이지에 저장돼 있던 탐색 위치가 수정되어야 하므로 비효율적이다.
그러므로 인덱스를 설정할 때는 조회 시 자주 사용하고, 고유한 값 위주로 설정하는 것이 좋다.
그럼 컬럼에 인덱스를 설정할 때 어떤 기준으로 설정하면 좋을까?
다음과 같은 기준으로 설정하는 것이 좋다.
카디널리티(Cardinality)
컬럼에 사용되는 값의 다양성 정도. 즉, 중복 수치를 나타낸다.
중복 정도가 낮으면 카디널리티가 높은 것.
→ 카디널리티가 높을수록 인덱스 설정에 좋은 컬럼이다.
선택도(Selectivity)
선택도 = 컬럼의 특정 값의 row 수 / 테이블의 총 row 수 * 100
데이터에서 특정 값을 얼마나 잘 선택할 수 있는지에 대한 지표.
5~10%가 적당하며, 선택도가 낮을수록 인덱스 설정에 좋은 컬럼이다.
활용도
해당 컬럼이 실제 작업에서 얼마나 활용되는지에 대한 값.
→ 활용도가 높을수록 인덱스 설정에 좋다.
중복도
중복 인덱스 여부에 대한 값.
같은 컬럼이어도 인덱스의 속성이 다르면 중복으로 인덱스 설정이 가능하다.
하지만 인덱스도 결국 메모리의 일부이므로 필요 없는 항목은 삭제하는 것이 좋다.
→ 중복도가 없을수록 인덱스 설정에 좋다.
인덱스의 대표적인 자료구조로는 해시 테이블(Hash Table)과 B+Tree가 있다.
해시 테이블(Hash Table)
key와 value를 한 쌍으로 데이터를 저장한다.
key값을 이용해 대응되는 value값을 구하는 방식이다.
(key, value) = (컬럼의 값, 데이터의 위치)로 구현한다.
하지만 데이터베이스에선 부등호(<, >) 연산이 자주 사용되는 반면 해시 테이블은 등호(=) 연산에 최적화되어 있기 때문에 잘 사용되지 않는다.
해시 테이블 내의 데이터들은 정렬되어 있지 않으므로 특정 기준보다 크거나 작은 값을 빠른 시간 내에 찾을 수가 없다.
B+Tree
오직 leaf node에만 데이터를 저장하고, leaf node가 아닌 node에서는 자식 포인터만 저장한다.
leaf node끼리는 Linked list로 연결되어 있다.
B+Tree에서는 리프 노드에만 데이터가 저장되기 때문에 중간 노드에서 key를 올바르게 찾아가기 위해 key값이 중복될 수 있다.
B+Tree를 사용할 경우 장점
리프 노드를 제외하고 데이터를 저장하지 않기 때문에 메모리를 더 확보할 수 있다.
→ 하나의 노드에 더 많은 포인터를 가질 수 있기 때문에 트리의 높이가 낮아져 검색 속도를 높일 수 있다.
Full Scan을 하는 경우 리프 노드끼리 Linked list로 연결되어 있기 때문에 선형 시간이 소모된다.
하지만 B+Tree의 경우, 특정 key에 접근하기 위해선 리프 노드까지 가야만 한다는 단점이 있다.
참고 자료
우리밋_woorimIT, “[DB Index] 우아한 애자일 - 정원지”, https://youtu.be/wYYXjWg2I4Q
“[DB] 11. 인덱스(Index) - (1) 개념, 장단점, B+Tree 등”, Rebro의 코딩 일기장, https://rebro.kr/167