예전에 진행하던 프로젝트에선 db의 크기가 크지 않아서 인덱스의 필요성을 못 느꼈는데,
업무를 진행하면서 api를 통한 트랜잭션의 처리를 많이 경험해보면서
트랜잭션의 처리 속도가 곧 ux와 이어져 서비스의 품질을 결정하겠구나 라는 생각을 가질 정도로 느린 트랜잭션 속도는 사용자로 하여금
굉장한 답답함을 느끼게 한다.
모든 시스템이 그렇듯 사이즈가 커지면 속도가 느려지는 건 당연하다.
그렇다고 해서 RDB가 제공하는 데이터의 신뢰성과 무결성을 포기할 수는 없다.
그리고 규모가 커진 서비스들도 속도를 포기할 수 없는 노릇이다.
1. 인덱스란
인덱스란 RDBMS의 검색 속도 향상을 위한 방법이다.
테이블의 칼럼을 색인해서 따로 파일로 저장을 하고, 테이블을 검색할 때, 해당 테이블을 전체 스캔하지 않고, 따로 색인한 파일을 검색하는 방법,
우리가 어떤 책을 구매할 때, 내용을 목차별로 나누는 것으로 생각하면 쉽다.
인덱스는 테이블과 논리적, 물리적으로 독립적이다.
테이블은 칼럼이 입력 순으로 쌓이게 되지만, 인데스는 key와 rowid 칼럼 두 개로 이루어져 오름, 내림차순 정렬이 가능하다.
여기서 key는 인덱스로 지정된 칼럼이다. MySQL에서 테이블을 만들게 되면,
FRM : 테이블의 구조가 저장된 파일
MYD : 실제 데이터 파일
MYI : 인덱스 정보파일 (사용 시)
위 3가지 파일이 생성되는데, 사용자가 인덱스를 사용해 검색을 하게 되면 MYI파일을 이용하여 검색을 한다.
인덱스는 key와 rowID만을 가지고 있는 파일이기 때문에, 테이블보다 적은 크기를 가지고 있다.
2. 인덱스를 사용해야 하는 이유
인덱스를 사용해야하는 이유는 앞서 말했듯이, 검색 속도를 빠르게 해 사용자에게 더 좋은 ux를 제공하기 위함이다.
그러나 단순히 빠르게 하기 위해 보다는 SQL select문이 작성되었을 때, DB가 어떻게 동작하는지 알아보자.
1. 사용자가 sql문을 작성하면 DB에서는 해당 sql이 DB에서 처음 사용된 문장인지, 아니면 기존에 사용됐던 문장인지를 판별한다.
(이전에 사용됐다면 parse 할 필요가 없기 때문이다.) 이 과정에서 syntax 에러는 없었는지, 테이블이나 뷰의 존재 등 sql 처리에 대한 무결성을 검사하게 된다.
2. 첫 단계가 성공적으로 마무리되면, DB는 메모리 영역의 버퍼 캐시 영역에서 사용자가 질의한 구문에 해당하는 데이터가 존재하는지 검색한다. 만약 존재하지 않는다면, 구문에 해당하는 테이블의 데이터를 버퍼 캐시로 가져와 복사한다.
3. 두 번째 단계가 마무리되면 캐시로 저장한 데이터를 읽어서 조건에 만족하는 데이터를 찾아 사용자에게 표시한다.
위 과정으로 미루어 보았을 때, DB가 느려지는 이유를 알 수 있다.
1. 데이터가 방대해져 검색해야 할 데이터가 많다.
2.SQL 구문이 기존에 parse가 되어있지 않은 구문이다. (사실 성능에는 별 영향이 없는 듯 함.)
여기서 속도가 느려지는 핵심적인 이유는 2번째 단계에서
버퍼 캐시 영역에서 만족하는 조건을 찾지 못해 테이블의 모든 데이터를 캐시에 복사 후 읽을 때, 굉장한 레이턴시가 발생된다.
그렇다면 이 과정을 피하기 위해, 인덱스를 사용하게 되면, 실행단계에서 DB는 테이블의 모든 데이터를 저장하지 않고 바로 인덱스를 활용해서 필요한 데이터만 재빠르게 읽은 후, 사용자에게 표시해줄 수 있다.
다시 말해,
인덱스가 없다 -> 모든 테이블의 데이터를 싹 다 복사한 다음부터 찾는다.
인덱스가 있다 -> key와 rowID 값을 통해 해당 key가 만족되는 rowID만을 골라 버퍼 캐시에 복사한 후, 사용자에게 표시.
3. 인덱스의 종류
1.Clustered index
물리적 정렬로 db에 데이터를 입력할 때, 해당 인덱스를 기준으로 정렬된다.
한 테이블의 오직 하나만 존재할 수 있으며 order by를 사용하지 않아도 데이터가 정렬되어있는 것은 바로 clustered index의 역할 때문이다. 물리적으로 정렬되어있어, 빠른 처리가 보장된다. 테이블의 pk와 같은 역할.
2.nonclustered index
1번과 달리 중복된 값을 가지면 한 테이블에 여러 개를 생성할 수 있다.
4. 인덱스의 장단점
인덱스는 key를 기준으로 검색 속도를 향상하는 목적이어서 정적인 테이블일수록 효과는 증대된다.
즉, 데이터의 변경 가능성이 없는 테이블에 인덱스 존재 가치는 상승하고, 기본키는 자동으로 인덱스가 된다.
정말 쉬운 예시로 인덱스가 자주 변경되면 파일로 저장된 파일의 크기에 자주 변경이 일어날 것이고, 이는 곧 자원에 대한 비용 증가로 이루어진다.
그리고 테이블의 규모가 커지면 인덱스 파일의 크기가 증가하는 것도 단점이다.
index가 계속 생성됨에 따라 select문 말고 다른 질의어를 사용할 때, 성능이 떨어질 수 있어, 사용할 때 신중해야 하고 자칫 DB에 엄청난 부하를 줄 수 있다.
그렇기 때문에 인덱스를 사용하는 것도 좋지만 sql의 동작 방식을 이해해서 쿼리문을 효율적으로 짜고, 테이블을 효율적으로 설계하는 것이 더 중요하다고 생각된다.
참고:
velog.io/@gillog/SQL-Index% EC% 9D% B8% EB% 8D% B1% EC% 8A% A4
'DataBase' 카테고리의 다른 글
SQL] 쿼리로 페이지네이션 하는 방법 (페이징) (0) | 2021.08.04 |
---|---|
Error] Could not create connection to database server. (0) | 2021.04.13 |
쿼리 속도 향상을 위한 방법들 (1) | 2021.02.14 |
MySQL]The MySQL server is running with the --read-only option so it cannot execute this statement (0) | 2021.02.08 |
Mybatis] MySQL] concat 문자열 검색 (1) | 2021.01.19 |
댓글