인덱스(Index)란 무엇이며, 왜 사용하나요?

김상욱·2024년 12월 14일

인덱스(Index)란 무엇이며, 왜 사용하나요?

인덱스(Index)는 데이터베이스에서 테이블의 데이터 검색 속도를 향상시키기 위해 사용되는 특수한 데이터 구조. 마치 책의 색인처럼 특정 데이터의 위치를 빠르게 찾을 수 있도록 도와주는 역할.

  • 파일 구조는 B-Tree 또는 Hash Table과 같은 자료 구조를 기반으로 설계. 일반적으로 B-Tree는 범위 검색과 정렬이 필요한 경우 사용되며, Hash Table은 정확한 값 검색에 유리합니다.
  • 데이터를 순차적으로 스캔하는 Full Table Scan 대신, 인덱스를 사용하여 필요한 데이터에 빠르게 접근
  • 인덱스를 생성하면 테이블 외에 별도의 저장 공간이 필요.
  • 데이터 삽입, 수정, 삭제 시 인덱스도 함꼐 갱신되므로, DML 작업 성능에 영향을 미칠 수 있다.

인덱스를 사용하는 이유

  • 특정 열에 대한 검색 속도를 비약적으로 향상
  • 정렬과 범위 검색 시 성능이 개선
  • UNIQUE Index를 사용하면 특정 열의 값이 중복되지 않음을 보장할 수 있음.
  • 조인 작업에서 연결 키(Column)에 인덱스를 설정하면 조인 속도가 빨라짐.
    -> WHERE 절이나 JOIN 조건에서 자주 사용되는 열.
    -> ORDER BY, GROUP BY, BETWEEN, LIKE 등에 자주 사용되는 열
    -> 이메일 주소나 주민등록번호 처럼 유일성 유지가 중요한 열.

인덱스의 단점

  • 테이블의 크기가 클수록 인덱스가 차지하는 공간도 커진다.
  • 데이터 삽입, 수정, 삭제 시 인덱스를 함께 갱신해야 하므로 추가 비용 발생.
  • 소량의 데이터나 자주 변경되는 데이터에서는 오히려 성능이 떨어질 수 있음.
    -> 테이블이 작은 경우, 인덱스보다 Full Table Scan이 더 효율적
    -> 값이 자주 수정되거나 삭제되는 열에 인덱스 설정하면 오버헤드 발생
    -> 중복값이 많은 경우 인덱스가 효과적이지 않을 수 있음.
-- 고객 테이블에 인덱스 생성
CREATE INDEX idx_customer_name ON Customers(Name);

-- 인덱스를 사용한 검색
SELECT * 
FROM Customers 
WHERE Name = 'John Doe';

인덱스의 종류

  • Primary Index : 기본 키로 설정된 인덱스. 기본적으로 유일성으로 보장하며, Null 값을 허용하지 않음.
  • Unique INdex : 특정 열의 값이 중복되지 않음을 보장
  • Composite Index : 여러 열을 결합하여 생성된 인덱스 ex) (Firstname, LastName)
  • Clustered Index : 테이블의 데이터가 실제로 정렬되어 저장되는 인덱스로 테이블당 하나만 생성 가능하다.
  • Non-clustered Index : 데이터는 원래 순서를 유지하고 별도의 구조로 저장

신입 및 취업 준비생 Java/Spring 백엔드 개발자 입장에서의 인덱스 학습과 실습 방안

인덱스(Index)는 데이터 검색 속도를 향상시키기 위한 핵심적인 데이터베이스 최적화 도구입니다. 신입 개발자나 취준생 입장에서 이를 학습하고 실습하려면, 이론과 실습을 병행하여 인덱스의 필요성을 이해하고, 실제 프로젝트에서 어떻게 활용하는지 익히는 것이 중요합니다.


실습 목표

  1. 인덱스의 역할 이해: 인덱스를 사용했을 때와 사용하지 않았을 때의 성능 차이를 확인.
  2. 인덱스 생성 및 관리: 다양한 유형의 인덱스 생성 및 활용.
  3. Spring 프로젝트와 연동: JPA/Hibernate 등에서 인덱스를 사용하는 방법.
  4. DML 작업 성능 영향 확인: 삽입, 수정, 삭제 작업 시 인덱스의 영향을 이해.

실습 준비

환경 설정

  1. Database: MySQL, PostgreSQL 또는 H2 Database (로컬 또는 Docker 환경).
  2. IDE: IntelliJ IDEA 또는 Eclipse.
  3. Spring Boot 프로젝트:
    • Spring Data JPA 사용.
    • H2 Database를 활용해 빠르게 실습.

실습 과제

1. 인덱스 없이 데이터 검색

  • 10만 건 이상의 샘플 데이터를 생성하여 Full Table Scan의 성능 문제를 체험.

SQL 스크립트

CREATE TABLE Products (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    description TEXT,
    price DECIMAL(10, 2),
    category VARCHAR(255)
);

-- 대량 데이터 삽입 (10만 건)
INSERT INTO Products (name, description, price, category)
SELECT CONCAT('Product', FLOOR(RAND() * 100000)), 'Sample description', RAND() * 100, 'Category'
FROM information_schema.tables t1, information_schema.tables t2
LIMIT 100000;

-- 검색 쿼리 실행 시간 확인
EXPLAIN SELECT * FROM Products WHERE name = 'Product12345';

결과

  • 검색 속도가 느리며, EXPLAIN 명령어로 Full Table Scan 확인.

2. 인덱스 생성 후 성능 비교

  • 동일한 테이블에 인덱스를 추가하고 검색 속도 비교.

SQL 스크립트

-- 인덱스 생성
CREATE INDEX idx_name ON Products(name);

-- 검색 쿼리 실행
EXPLAIN SELECT * FROM Products WHERE name = 'Product12345';

결과

  • 검색 속도가 빨라지고, EXPLAIN 결과에 인덱스 사용이 표시됨.

3. Spring Data JPA에서 인덱스 사용

  • JPA 엔티티에서 인덱스 설정 및 조회 성능 확인.

Entity 코드

import jakarta.persistence.*;

@Entity
@Table(name = "products", indexes = {
        @Index(name = "idx_name", columnList = "name")
})
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    private String description;
    private Double price;
    private String category;

    // Getters and Setters
}

Repository 코드

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByName(String name);
}

Test 코드

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;

@SpringBootTest
public class ProductIndexTest {

    @Autowired
    private ProductRepository productRepository;

    @Test
    public void testSearchWithIndex() {
        long startTime = System.currentTimeMillis();
        productRepository.findByName("Product12345");
        long endTime = System.currentTimeMillis();
        System.out.println("Search Time: " + (endTime - startTime) + "ms");
    }
}

결과

  • 데이터베이스의 인덱스 설정에 따라 검색 속도가 크게 달라지는 것을 확인.

4. DML 작업과 인덱스의 영향 확인

  • 인덱스가 있는 상태에서 대량의 데이터 삽입 및 수정 시 성능 확인.

SQL 스크립트

-- 대량 데이터 삽입
INSERT INTO Products (name, description, price, category)
SELECT CONCAT('NewProduct', FLOOR(RAND() * 100000)), 'Description', RAND() * 100, 'NewCategory'
FROM information_schema.tables t1, information_schema.tables t2
LIMIT 50000;

-- 대량 데이터 업데이트
UPDATE Products SET category = 'UpdatedCategory' WHERE category = 'NewCategory';

결과

  • 삽입 및 수정 작업이 느려질 수 있음. 이는 인덱스 갱신 비용 때문임.

5. 복합 인덱스 실습

  • 다중 컬럼 검색에서 복합 인덱스의 활용 효과 확인.

SQL 스크립트

-- 복합 인덱스 생성
CREATE INDEX idx_name_category ON Products(name, category);

-- 복합 조건 검색
EXPLAIN SELECT * FROM Products WHERE name = 'Product12345' AND category = 'Category';

결과

  • 단일 컬럼 인덱스보다 복합 조건에서 성능이 향상됨.

추가 실습 아이디어

  1. 커버링 인덱스(Covering Index) 실습
    특정 조회 쿼리에서 인덱스만으로 필요한 데이터를 처리하도록 설정.

  2. 클러스터형 vs 비클러스터형 인덱스 실습
    MySQL의 InnoDB 클러스터형 인덱스와 비교해 보기.

  3. 인덱스 조정
    인덱스가 과도하게 설정된 경우 성능 저하를 시뮬레이션하고 최적화 방법 학습.

  4. Spring Cache와 연동
    인덱스를 사용한 쿼리를 캐싱해 성능 최적화를 테스트.


실습 결과 활용

  • 블로그 글 작성: 인덱스 실습 결과를 정리하여 공유.
  • 깃허브 프로젝트: Spring Boot와 JPA를 활용한 실습 코드를 업로드.
  • 면접 대비: "인덱스를 실제로 테스트해본 경험"을 면접 답변에서 활용.

결론

인덱스 실습은 단순한 이론 학습을 넘어, 실질적인 검색 성능 최적화DML 작업 성능 변화를 이해하는 데 도움이 됩니다. 이러한 실습을 통해 백엔드 개발자로서 데이터베이스 성능 최적화 역량을 강화할 수 있습니다.

0개의 댓글