인덱스 인덱스~~
- 개발/읽기 성능 개선
- 2025. 12. 8. 12:43
오래 기억에 남으려고 이해가 가지 않는것들은 이해가 갈때까지 공부하는 방식을 선택하였고, 계속 복습을 반복하는 형식으로 진행하였습니다. 하지만 여기에는 아주 치명적인 문제가 있었습니다. 그것은 생각보다 시간이 오래걸렸습니다. 보통 토요일 부터 시작해서 월요일까지 정리를 마치는데 나오는 결과물이 생각보다 좋지는 않았던거 같습니다. 그래서 방법을 다시한번더 바꾸려고 합니다.
그렇다고 해서 GPT에 돌린결과를 그대로 쓸 생각은 없습니다. 그렇게 해버리면 공부하는 의미가 없기 때문이죠. 조금더 고민해보고 진행해보겠습니다.
일단 학습을 하려고 하는 범위 부터 말씀드리고 깊게 학습하는 방식으로 변경하는게 좋다고 생각합니다.
학습할 내용은 다음과 같습니다.
Index, SQL Injection, Statement vs PrepareStatement, 효과적인 쿼리 저장, 옵티마이저입니다.
간단하게 어떤 정보인지부터 알아보고 자세하게 학습하는 시간을 가져보겠습니다.
인덱스: 데이터를 정렬된 구조(B-Tree 등) 로 저장해 검색 범위를 빠르게 줄여주는 장치
SQL injection: 입력값이 SQL 문장에 그대로 삽입되면서 공격자가 쿼리를 변조하는 취약점
Statement vs PrepareStatement:
Statement
- 실행할 때마다 쿼리를 새로 파싱·최적화
- SQL Injection 취약
PrepareStatement
- 쿼리 구조를 먼저 컴파일하고 실행 계획을 캐싱
- 파라미터 바인딩으로 Injection 원천 차단
효과적인 쿼리 저장: DB 또는 애플리케이션이 쿼리 구조나 실행 계획을 재사용하여 불필요한 파싱·최적화를 줄이는 방식.
옵티마이저: DB가 쿼리를 실행할 때 가장 비용이 적은 실행 계획을 자동으로 선택하는 엔진
라고한다. 그렇다면 이들은 어떻게 이야기를 꾸미면 오래기억이 남을 수 있을까?
개발하다보면, SQL쿼리를 작성하고 GET API를 작성했을때 비이상적으로 느린 경우가 종종 발생하게 되어집니다.
이럴때 확인 할 수 있는 방법 중 하나가 인덱스를 설정하는 행위입니다. 이제 본격적으로 인덱스에 대해 알아봅시다.
여기서 DB는 RDBMS를 말합니다. NOsql아님
인덱스:는 보통 색인이라고 불려집니다. 이는 책 뒤쪽을 보시면 쉽게 이해 할 수 있습니다. 거기에는 A-Z 혹은 가 - 허로 어떤 위치에 어떤 내용이 있는지 쉽게 알 수 있게 되어있습니다.

이것으로 우리는 인덱스는 키와 값으로 되어 있다는 사실을 알수 있습니다. 여담으로 이것을 활용해 조회하는 행위를 인덱스 기반 조회라고도 한다고 합니다. 인덱스는 이게 전부입니다. 인덱스를 CREATE INDEX ... 요렇게 지정하게 되면 어떻게 DB는 이것이 인덱스인지 알 수 있을 까요?
바로 DB는 CREATE INDXE 실행 시 인덱스 정보를 시스템 카탈로그에 등록을 하게 됩니다. 시스템 카탈로그는 메타 데이터를 모아놓은 곳이라고 합니다. 혹자는 이걸 DB의 두뇌라고 표현하기도 합니다. 암튼 이때, 인덱스 타입, 대상 컬럼, 저장 구조가 모두 메타 데이터로 남기 때문에 DB 엔진과 옵티마이저는 이를 인덱스 객체로 인식하게 되고 쿼리 최적화 과정에 활용되어집니다. 즉, 메타 데이터 등록이 DB가 인덱스를 인지하는 근거가 되어집니다.
결국, CREATE INDEX쿼리를 실행하게 되면, DB에서 이것을 기억하고 옵티마이저가 실행해주는 시스템으로 이해가 되어집니다.
(DB자체에서 인덱스를 기억할수는 없고, 시스템 카탈로그에 저장이 되어집니다.)
그래 좋습니다. 인덱스를 시스템 카탈로그에 저장하는거 까지 ok입니다.
그렇다면 어떻게 찾을 수 있을까요? 인덱스는 다음과 같이 작성할 수 있습니다.
가장 기본적인 방법은 CREATE INDEX idx_user_name ON users (name); 입니다.
이름을 정하고, name을 인덱스로 지정한다는 뜻이게 되는거죠. users은 테이블입니다. 이것이 말하는 바는 여러개를 설정해도 같은 테이블내에서만 가능하다는 뜻이 되어집니다. 설명은 하지는 않겠지만 다음과 같은 쿼리를 사용할 수 있다고 합니다. (특수한 경우는 제거했습니다. 모든 DB에서 사용이 가능합니다.
기본 : CREATE INDEX idx_user_name ON users (name);
다중 : CREATE INDEX idx_user_name_age ON users (name, age);
중복 허용 하지 않는 경우: CREATE UNIQUE INDEX idx_user_email_uniq ON users (email);
정렬 최적화 이용: CREATE INDEX idx_order_created_desc ON orders (created_at DESC);
등등이 존재합니다. 등등으로 말씀드리는 이유는 DB마다 특색있는 인덱스 생성 방법들이 존재한다고 합니다. (확인한거는 postsql이지만..)
다시 돌아왔습니다. 위에서 옵티마이저가 실행을 시켜준다 말했었는데 옵티마이저는 과연 무엇일까요?
DB가 쿼리를 실행할 때 가장 비용이 적은 실행 계획을 자동으로 선택하는 엔진이라고 위에서 적었습니다. 그렇다면 옵티마이저는 과연 어떤것을 말하는 걸까요?
옵티마이저는 3가지 역할을 한다고 합니다.
1) 가능한 모든 실행 방법을 "생성"한다
2) 각 실행 방식의 비용을 계산한다 (Cost Model)
3) 최종적으로 가장 비용이 낮은 실행 계획을 선택한다
그렇다면 이것은 브루트포스라고 볼수 있을까요? 모든 경우의 수를 찾아서 거기서 가장 빠른 것을 찾으니..
하지만 옵티마이저는 브루트포스처럼 보이지만 실제로는 전체 탐색을 하지 않습니다. 가능한 계획 공간을 제한하고, 통계 정보를 기반으로 비용이 큰 경로는 조기 제거하며, 남은 후보들만 비용 계산을 통해 선택하는 '비용 기반 탐색 엔진(CBO)'입니다.
즉, 브루트포스적 요소는 있으나 전체 탐색은 아니며, 동적 계획법과 휴리스틱 기반 pruning을 사용한다고 합니다.
그렇다면 쿼리를 생성하고 그것을 가장 빠른 경우를 옵티마이저를 통해 해결할수 있다고 배웠습니다. 그렇다면, 쿼리를 어떻게 저장하는 방법이 가장 효율적일까요? 아주 간단하게 생각했을때 API를 만드는 것처럼 데이터를 발송하고 저장하는 방식일까요?
엄밀히 말하면 그러면 안됩니다. SELECT문안에는 수많은 키워드들이 존재합니다. 그렇다는건 얘네가 어떻게 실행이 되는지 알아야 한다는뜻입니다. 왜냐하면 SELECT ~~~는 문법이고 실제로 DB가 이해하는건 다른 영역이기 때문이죠 이는 마치 자연어와 기계어가 분리되어있는거와 비슷한 느낌입니다.
이를 다시 말하면 개발자는 다음과 같은 순서로 이해가 되어진다고 합니다.
SELECT → FROM → JOIN → WHERE → GROUP BY → HAVING → ORDER BY
하지만 DB는 다음과 같이 이해해야 하죠.
FROM -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
이 과정을 '실행 계획 기반(Execution-Plan Based)'이라고 합니다. SQL의 각 키워드는 실제로 실행 가능한 절차적 단계로 변환되어야 하고, 옵티마이저는 이 중 가장 비용이 낮고 효율적인 실행 계획을 자동으로 선택한다. 사실 강제로 실행계획을 바꿀 수 있다고는 하는데 비추천한다고 합니다. 왜냐하면 옵티마이저가 일반 개발자보다 똑똑한 사람이 만들었는데...ㅎㅎ
이건 내 생각이지만 나중에 여기에 AI가 들어갈지도 모르겠다는 생각이 든다.. 그럼 DB 실행 속도가 지금보다 빨라지지 않을까?
그리고 도중에 넘어갔지만, 모든 칼럼에 인덱스를 전부 발라 버리면 어떻게 될까? 많은 문제가 야기 될 수 있다고 한다.. 자고로 인덱스는 읽기 성능은 올리지만 쓰기 성능을 떨어뜨리는 주범이기 때문에 신중하게 수정해야 한다.
'개발 > 읽기 성능 개선' 카테고리의 다른 글
| 인덱스 혼자 끄적이기 (2) | 2025.08.17 |
|---|---|
| 기존 테스트.. (4) | 2025.08.15 |
| 어떤 방법으로 성능 개선하는것이 좋을까? (9) | 2025.08.15 |