복습 - Index_type에 올 수 있는 것들
BTREE (B-Tree)
- 기본값 (지금 테이블도 전부 BTREE)
- 데이터를 트리 구조로 정렬해서 저장
- 범위 검색, 정렬, 동등 비교 모두 잘됨
WHERE pub_date > '2024-01-01'
WHERE pub_date = '2024-01-01'
ORDER BY pub_date DESC
HASH
- 데이터를 해시값으로 변환해서 저장
- 동등 비교만 빠름, 범위 검색 불가
- MySQL InnoDB는 HASH 인덱스 직접 생성 불가 (MEMORY 엔진만 가능)
WHERE announce_id = 123 -- ✅ 매우 빠름
WHERE announce_id > 123 -- ❌ 인덱스 못 탐
ORDER BY announce_id -- ❌ 정렬 불가
FULLTEXT
- 텍스트 전문 검색 전용
- LIKE '% 검색어%' 대신 사용
- 형태소 분석, 자연어 검색 가능
-- LIKE는 인덱스 못 탐
WHERE title LIKE '%공지%' -- ❌ 느림
-- FULLTEXT는 가능
WHERE MATCH(title) AGAINST('공지') -- ✅ 빠름
SPATIAL
- 지리 공간 데이터 전용 (위도, 경도 등)
- 거의 GIS 관련 서비스에서만 사용
WHERE ST_Contains(location, ST_GeomFromText('POINT(37.5 127.0)')) -- ✅
Announce

해당 테이블에는 클러스터 인덱스를 제외하고 idx_announce_pub_date , idx_announce_view_num index가 존재한다
각각을 알아보자
idx_announce_pub_date
- Non_unique 가 0 임으로 일반 인덱스
- 복합 인덱스가 아님으로 Seq_in_index = 1
- pub_date 칼럼이 인덱스로 걸려있다
- Collation 이 D라서 인덱스가 DESC로 정렬되어 있다
- Cardinality 가 252001이라서 적절한 칼럼에 인덱스를 잘 걸었다
- Null 이 Yes 라 Null 값을 허용하고
- 인덱스 타입은 기본값인 BTREE 다
idx_announce_view_num
- Non_unique 가 0 임으로 일반 인덱스
- 복합 인덱스가 아님으로 Seq_in_index = 1
- view_num 칼럼이 인덱스로 걸려있다
- Collation 이 D라서 인덱스가 DESC로 정렬되어 있다
- Cardinality가 4851이라서 그리 효율이 높아 보이지는 않는다. 옵티마이저가 해당 인덱스를 무시하고 FullScan을 할 가능성이 있다 EXPLAIN을 통해 실행 계획을 확인해 보자
- 인덱스 타입은 기본값인 BTREE 다
idx_announce_view_num을 설계한 이유는 다음 쿼리 때문이다
@Override
@Transactional(readOnly = true)
public List<PopularAnnounceRedisDto> findPopular(int limit) {
return queryFactory
.select(Projections.constructor(PopularAnnounceRedisDto.class,
announce.id,
announce.title,
announce.reqstEndDate,
announce.viewNum))
.from(announce)
.orderBy(announce.viewNum.desc())
.limit(limit)
.fetch();
}
해당 쿼리의 실행 계획을 확인해서 index를 타지 않으면 해당 인덱스를 삭제하자
왜냐면 index는 select 성능에는 영향을 주지만 INSERT, UPDATE, DELETE 에는 비용이 더 발생하기 때문이다

실생계획을 보면 index를 타고 있긴 하지만 Index FullScan이다
FullScan 보다는 좋긴 하지만 여전히 안 좋다.. 그러면 없애는 게 맞을까?? 지금처럼 IndexFullscan으로 두는 것이 좋다
이유
- Update 가 발생하는 Batch는 API로 이뤄지지 않기 때문에 클라이언트가 느끼는 응답시간에는 영향이 없다
- Index를 사용하면 정렬도 자동으로 해주기 때문에 앞에서 3개만 읽고 멈춘다
인덱스 없애는 순간 252,001건 전부 읽고 정렬하기 때문에 Index유지가 더 좋다!
Business

UKeiijvd0rro9t2s4f88wqvguyf
- Non_unique 가 0 임으로 이건 유니크 제약 조건이다
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id",nullable = false, unique = true)
private Member member;
이 코드에서 유니크 제약 조건이 붙었을 것이다!
FKfu8nqhj75gvgk8arjm4i9lrw8
- Non_unique 가 1 임으로 일반 인덱스
- Seq_in_index 가 1 임으로 복합 인덱스는 아님
- Column_name을 통해 business_code 칼럼에 인덱스가 붙여 있다
- 그런데 Cardinality 가 250 그 이유는 businessCode의 전체 개수가 250개 이기 때문이다!
Document

idx_document_announce_id
- Non_unique 가 1이라 일반 인덱스
- Seq_in_index 가 1 이라 복합인덱스는 아님
- index가 걸려있는 칼럼은 announce_id
Member

UKmbmcqelty0fbrvxp1q58dn57 t
이것도 역시 유니크 제약 조건!!
Member_document_check

UKkvice74iivt4l67uwiv1uhfha
- 이건 좀 신기했다!! 유니크 인덱스인데 신기한 건 복합 인덱스 다
- 즉 복합 유니크 제약 조건 소리인데!!! 신기한건 복합인덱스를 걸면 걸린 칼럼만큼 행이 생긴 다는 것이다
- 같은 key 이름으로 생기는데 복합인덱스의 순서는 Seq_in_index를 보면 알 수 있다
- 이 제약조건의 이름은 member와 document에 복합 인덱스를 걸어서 중복으로 처리되는 것을 막으려고 한다
FKkh1rb30ib27arn0bmqupva98 c
- 일반 인덱스
- 복합 인덱스도 아니고
- document_id 칼럼에 걸려 있다
Member_favorite

UKs72u9r3gt3l4c4b5onq0maqc1
- 위에서 본 것과 같이 유니크 복합 인덱스!!! member_id와 announce_id 둘 다 걸려 있다!!
idx_member_favorite_announce_member
- 이건 복합 인덱스!!!!이다
- announce_id를 첫 번째 member_id를 두 번째로 설정되어 있다
- 쿼리 어디선가 announce_id와 member_id 두 개를 조건으로 하는 쿼리가 있을 것이다
- 예상하건대 explain으로 해당 쿼리를 돌려보면 range 가 뜰 것 같다!!
Sos

FK78fkgypwngqcm9wtmv8v5fet2
- member_id에 걸린 일반 인덱스
Sos_image

FK250tvjhcu89vemlpiw2y3eb4v
- sos_id에 걸린 일반 인덱스

'🖥️ 컴퓨터 공부' 카테고리의 다른 글
| 나머지 API 들 부하테스트 (0) | 2026.04.25 |
|---|---|
| MySql- Show Index , Explain필드 분석 (0) | 2026.04.24 |
| 인덱스의 종류 (0) | 2026.04.24 |
| B+Tree란 ? (0) | 2026.04.24 |