티스토리 뷰

 

 

인덱스의 특징을 살펴보면,

1. 인덱스는 질의 결과를 빠르게 찾는데 목적이 있다.

2. 데이터베이스에 레코드가 삽입, 삭제될 때마다 인덱스가 변경되어야 한다.

3. 그런데 데이터베이스에서 인덱스는 별도의 자료구조(B-Tree)형태로 관리하게 된다. 인덱스 자료구조도 디스크에 저장하여, 질의가 있을 경우에 읽어와서 사용하게 된다.

 

여기서 3번이 인덱스가 많아지면 문제가 될 수 있는 부분에 해당한다.

한 테이블에 인덱스를 많이 걸면 성능이 안좋아진다는 얘기를 많이 들어봤을 것이다.

 

 

어떠한 이유로 성능이 안좋아지는 것일까 ?

 

 

DB를 직접 만든다고 생각해보자.

DB는 거대한 list에서 특정 item 을 찾기 위한 시스템이다.

List <User> users;

 

list의 크기가 작을 때는 그냥 for-loop를 돌면서 일일히 비교하면 되겠지만,

for(int i=0; i<users.size(); i++){
	if(users[i].name == inName)
    	return users[i];
}

 

list의 크기가 커지거나 빠른 검색이 필요하다면 HashMap 같은 것이 필요하게 된다.

Hashmap<String, User> nameIndex;
nameIndex.get(inName, outUser);

검색이 빨라진 것까지는 좋은데 여기서 단점이 하나 생기게 된다. 데이터를 추가할 때마다 인덱스에 추가를 해줘야 한다는 것이다.

users.add(newUser);
nameIndex.add(newUser.name, newUser);

모든 컬럼에 인덱스를 추가해 준다면 아래처럼 작동할 것이다.

ageIndex.add(newUser.age, newUser);
jobIndex.add(newUser.job, newUser);
...

 

이렇게 되면,

자칫 본체보다 인덱스가 더 큰 용량을 필요로 하게 될 것이다. 거대한 데이터를 처리하기 위해 DB를 사용하는 것인데, 본체보다 더 거대한 인덱스가 생기게 되는 것이다.

 

추가 뿐만 아니라 수정할 때에도 일일히 인덱스에서 찾아 기존 키를 삭제하고 새로운 키를 넣어줘야 할 것이다.

DB가 알아서 내부적으로 처리해주기 때문에 괜찮아보이는 것일 뿐 직접 프로그래밍 한다고 생각해보면 끔찍한 일이 벌어지고 있는 것이다.

 

이런 방식으로 동작한다면, 검색은 어떻게 될까?

 

예를 들어 지난주에 접속해서 게임을 플레이했던 유저를 찾아서 보상을 준다고 해보자. 단순하게 게임 플레이 시간에 인덱스를 걸어 레코드를 추가해본다고 한다면,

gameRecord.setPlayTime = new Date();
playTimeIndex.add(gameRecord.getPlayTime, gameRecord)

10000명의 유저가 하루 100번 플레이하면 playTimeIndex에 들어가게 되는 키 개수는 백만개이다. 1주일이면 7백만개, 1년이면 25억정도가 된다. 1년정도 데이터가 쌓여있다면 25억개의 키 중에서 특정 기간에 포함되는 경우를 찾아야 하는데, 말도 안되는 일이 일어나게 된다.

 

이것이 바로 아무 컬럼에나 인덱스를 걸면 안되는 이유이다.

 

만약 플레이 시간(time) 대신 플레이한 주(week)컬럼에 인덱스를 걸면 키는 25억개에서 52개정도로 급격하게 줄어들게 된다. 52개의 검색은 순식간이다.

 


 

위에서 확인할 수 있듯이, 레코드의 삽입 삭제가 이루어질 때마다, 해당 레코드에 의해 변경되어야 하는 모든 인덱스에 연산을 취하고 그 결과를 디스크에 다시 저장해야 한다.

 

 

예를 들어 테이블에 주키(Primary Key)만 있는 경우에, 레코드 삽입 삭제시 일어나는 연산을 아주 간단히 나타내면 다음과 같다.

레코드 1개 삽입 : 테이블에 레코드 추가 저장 -> 주키 인덱스 삽입 연산 후 저장
레코드 1개 삭제 : 테이블에 레코드 삭제 -> 주키 인덱스 삭제 연산 후 저장

 

이제 테이블에 또 다른 키에 대한 인덱스 A와 인덱스 B가 있다고 가정해보면 다음과 같이 된다.

레코드 1개 삽입 : 테이블에 레코드 추가 저장 -> 주키 인덱스 삽입 연산 후 저장 -> 인덱스 A삽입 연산 후 저장 -> 인덱스 B 삽입 연산 후 저장
레코드 1개 삭제 : 테이블에 레코드 삭제 -> 주키 인덱스 삭제 연산 후 저장 -> 인덱스 A삭제 연산 후 저장 -> 인덱스 B 삭제 연산 후 저장

 

DBMS의 구현에 따라 각 연산의 속도차이가 있을 뿐, 일의 과정은 이와 동일할 것이다.

즉, 인덱스가 많아지면 많아질수록 레코드 삽입과 삭제시 할 일이 많아지는데, 이 일이 모두 디스크I/O와 관련이 있다.

 

따라서 인덱스를 많이 작성하게 되면 삽입/삭제에서 성능이 차이가 날 수 밖에 없다. 다만 검색에서는 많은 인덱스를 사요할 수 있기 때문에 다양한 검색 조건에서 성능을 낼 수 있을 것이다.

사용하는 질의어가 대부분 프로그래밍에 의해서 결정되는 것이라면, 이미 어떤 열(속성, 컬럼)에 의해 검색되는지 알고 있으므로, 이에 맞게 인덱스를 생성해야 효율적으로 사용할 수 있을 것이다.

 

그래서 데이터베이스를 사용하려고 하는 성격, 검색 비중이 높은지 혹은 삽입/삭제가 빈번하게 일어나는지 에 따라 인덱스를 적절하게 생성해줘야 한다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함