HW

인덱스로 조회 성능 높이기

 

 

인덱스란?

  • 인덱스는 테이블안의 데이터를 더 빠르게 찾기 위해 사용하는 자료구조이다.
  • 특정 컬럼을 기준으로 정렬된 별도의 자료구조를 만들어서, WHERE 조건이나 검색 같은 쿼리를 훨씬 빠르게 만든다.
  • 적용 대상은 테이블의 특정 컬럼이며 자주 사용되는 컬럼에 적용되면 좋다.
  • 인덱스를 만들어도, 평소처럼 쿼리 날리면 된다. DB가 내부적으로 인덱스를 자동으로 활용해서 Full table scan이 아니라 인덱스를 따라서 빠르게 찾아간다.
  • 인덱스를 사용 못하는 경우
    • LIKE “%abc” : 앞에 와일드카드 붙은 경우
    • WHERE LOWER(email) = ‘abc’ : 함수를 감싸면 인덱스를 못 쓴다.
    • OR 여러 개 묶인 복잡한 WHERE 절

⇒ 이런 경우에는 인덱스 무시하고 그냥 Full table scan 쓸 수도 있음 그래서 EXPLAIN으로 실제 인덱스를 쓰는지 확인해야함.

⇒ type이 Using index면 인덱스를 활용하는 거고, type = ALL이면 full table scan이다.

EXPLAIN SELECT * FROM users WHERE email = 'abc@gmail.com';

⇒ Mysql 8부터는 실행시간까지 포함된 상세 분석 결과 출력 가능하다.

EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'abc@gmail.com';
  • 장점 : 쿼리 성능 대폭 향상, 데이터가 많아질수록 효과가 좋다.
  • 단점 : 인덱스를 많이 만들면, INSERT, DELETE, UPDATE 성능이 낮아진다. 또한 인덱스도 저장공간을 차지한다.

 


뷰란?

  • 복잡한 쿼리를 단순하게 만들고, 재사용성과 가독성을 높이기 위한 도@ㄷ
  • SELECT 쿼리를 마치 테이블처럼 가상화 한 것을 의미한다.
CREATE VIEW active_users AS
SELECT id, name FROM users WHERE status = 'ACTIVE';

⇒ 이렇게 하면 이젠 select * from users; 만 쳐도 된다.

  • 적용 대상은 여러 테이블을 JOIN 한 경우거나, WHERE이나 GROUP BY가 복잡한 쿼리를 자주 쓰는 경우이다.
  • 뷰는 INSERT, UPDATE 안된다. 읽기 전용이다. 컬럼 변경하고 싶으면 뷰를 재생성한다.
  • 장점: 코드 재사용성이 높고, 가독성이 좋고 보안에도 유용하다.
    • 보안에 유용한 이유는: 민감한 정보 노출이 제한된다.
  • 단점: 뷰 자체는 성능 향상 도구가 아니다. 또한 뷰 안의 쿼리가 복잡하면, 또 성능 저하된다.

 


인덱스 VS 뷰

  • 데이터 검색 속도 개선이 목적이면 → 인덱스
  • 복잡한 쿼리 깔끔하게 쓰려면 → 뷰
  • 자주 조회하는 조건이 있으면 → 인덱스, 뷰
  • INSERT, UPDATE가 많은 테이블 → 인덱스 쓰면 안되고, 뷰는 상관 없다. (영향 거의 없음)

 


인덱스는 SQL에서 직접 생성해야한다.

CREATE INDEX idx_user_email ON users(email);
  • DB 구조에 영향을 주는 것이기 때문에, Spring 코드에서는 할 수 없다.
    • DDL은 스프링 코드에서 할 수 없음
  • JPA에서는 @Table 어노테이션에서 인덱스 지정 가능하다. 이건 Hibernate가 스키마를 자동 생성할 때 반영된다.
@Table(
	name = "users"
	indexs = @Index(name = "idx_user_email", columnList = "email")
	)

 

 

 


뷰도 기본적으로 SQL에서 생성해야한다.

CREATE VIEW user_summary AS
SELECT id, name, created_at FROM users WHERE statuss = "ACTIVE";
  • DB 구조에 영향을 주는 것이기 때문에, Spring 코드에서는 할 수 없다.
    • DDL은 스프링 코드에서 할 수 없음
  • JPA에서는 @Table 어노테이션에서 인덱스 지정 가능하다. 이건 Hibernate가 스키마를 자동 생성할 때 반영된다.
@Entity
@Table(name = "user_summary")
public class UserSummary {
	private Long id, 
	private String name, 
	private LocalDateTime createdAt;
}