← 전체 글로 돌아가기

웹 개발

데이터베이스 인덱스가 없거나 제대로 안 탈 때

쿼리가 느려지거나 데이터를 못 찾을 때, 인덱스 문제가 원인인지 빠르게 진단하는 방법을 정리했다.

쿼리가 갑자기 느려지거나, 조인 성능이 떨어지는 경우가 많다. 데이터가 몇 천 건일 때는 눈에 띄지 않지만, 몇 백만 건이 되면 인덱스의 유무가 생사를 가른다.

Prisma에서 마이그레이션 상태 확인

먼저 현재 스키마와 데이터베이스의 상태가 일치하는지 본다.

npx prisma validate
npx prisma migrate status
npx prisma migrate reset  # 데이터가 없으면

마이그레이션이 pending 상태면, 인덱스를 포함한 스키마 변경이 아직 적용되지 않은 것이다.

실제 데이터베이스에서 인덱스 목록 보기

PostgreSQL 기준:

-- 모든 인덱스 조회
\d table_name

-- 더 자세한 정보
SELECT
  indexname,
  indexdef
FROM pg_indexes
WHERE tablename = 'users';

MySQL이면:

SHOW INDEXES FROM table_name;

Prisma 스키마에 @@index 디렉티브가 있어도, 마이그레이션이 실행되지 않았으면 실제로는 없다.

쿼리 실행 계획으로 인덱스 사용 확인

인덱스가 있어도, 쿼리 최적화기가 사용하지 않을 수 있다.

EXPLAIN ANALYZE SELECT * FROM users WHERE email = '[email protected]';

결과에서:

  • Seq Scan : 전체 테이블 스캔 (인덱스 미사용)
  • Index Scan : 인덱스를 탔다
  • rows : 실제 조회 행 수
  • actual time : 실제 실행 시간

데이터가 적으면, PostgreSQL이 전체 테이블을 스캔하는 게 더 빠르다고 판단할 수 있다. 이 경우 데이터가 많아질 때까지는 인덱스가 필요 없을 수도 있다.

Prisma 스키마에서 인덱스 정의 확인

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique  // 고유 인덱스 자동 생성
  name  String

  @@index([name])  // 복합 인덱스
  @@index([email, createdAt])
}

@unique는 자동으로 인덱스를 만들고, @@index는 명시적으로 지정할 수 있다.

마이그레이션 파일 검사

생성된 마이그레이션 파일을 직접 본다.

ls prisma/migrations/
cat prisma/migrations/*/migration.sql

CREATE INDEX 구문이 실제로 있는지 확인한다. 없다면 Prisma 스키마의 인덱스 정의가 마이그레이션에 반영되지 않은 것이다.

성능 영향 측정

인덱스를 추가한 후, 실제로 쿼리가 빨라지는지 확인한다.

# 마이그레이션 적용
npx prisma migrate deploy

# 테스트 쿼리 실행 (시간 측정)
time npx prisma studio  # 또는 직접 쿼리 실행

쿼리 시간이 ms 단위에서 변한다면, 인덱스가 제대로 작동하는 것이다.

다중 컬럼 인덱스의 순서 중요

@@index([userId, createdAt])

이 인덱스는 WHERE userId = 1 AND createdAt > now() 쿼리에는 효과적이지만, WHERE createdAt > now() 만으로는 인덱스를 제대로 탈 수 없다. 쿼리 패턴에 맞춰 인덱스 컬럼 순서를 설계해야 한다.