자, 엔티티를 만들고 인덱스를 걸어보자. 그 전에 인덱스를 사용하는 이유가 무엇인지부터 좀 이해해보자.
아래 내가 작성한 링크에 인덱스를 사용하는 이유와 인덱스를 만들때 사용되는 구조에 대한 간략한 글을 작성했었다.
자, 이제 인덱스를 왜 만들고 인덱스가 왜 필요하고 어떻게 만들어지는지 어느정도 감을 잡았다면 JPA와 인덱스를 같이 사용해보자.
다음 코드를 보자. 매우 간단한 엔티티이다.
@Entity
@Table(name = "members", indexes = {
@Index(name = "idx_username", columnList = "username")
})
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String email;
}
- 지금 Member엔티티는 username 필드를 인덱스로 설정했다.
- 이제 검색 조건에 username이 들어가고, 그 빈도수가 잦다면, 인덱스를 통해 검색 최적화를 기대해 볼 수 있다.
그런데, 이런 상황도 있을 수 있다. "어? 저는 username, email 이 두개를 검색 조건으로 같이 사용하는 쿼리가 훨씬 많아요!" 그런 경우엔 복합 인덱스를 사용해서 조금 더 최적화를 기대해볼 수 있다. 다음 코드를 보자.
@Entity
@Table(name = "members", indexes = {
@Index(name = "idx_username_email", columnList = "username, email")
})
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
// Getters and setters omitted for brevity
}
- 이번에는 username, email 이 두가지를 사용해서 복합 인덱스를 만들었다.
- 이 경우, 검색 조건으로 username, email 둘 다 사용될 때 가장 최적의 성능을 발휘한다.
- username만 검색 조건에 들어가는 경우엔 이 복합 인덱스를 사용할 순 있지만 username만 가지고 인덱스를 만든 단일 인덱스보단 성능이 덜 나올 수 있다. 여기서 인덱스 순서와 성능에 대한 이야기를 해볼 수 있다.
- 그리고 이 경우, 검색 조건에 email 만 사용되는 경우 이 인덱스를 사용할 수 없다. 인덱스가 username을 먼저 기준으로 하기 때문이다.
복합 인덱스를 사용할 때 인덱스 컬럼 순서
지금처럼 username, email 순으로 username을 먼저 인덱스 순서로 지정하면, 인덱스는 username을 먼저 기준으로 정렬하고, 그 다음으로 email을 정렬하는 구조가 된다. 그래서 실제 사용 패턴에 따른 인덱스를 설계할 땐 다음과 같이 고려해볼 수 있다.
- username을 더 자주 검색하는 경우: username, email 순으로 설정하는 것이 효율적이다.
- email을 더 자주 검색하는 경우: email, username 순으로 설정하는 것이 효율적이다.
누군가는 이런 오해를 한다. 필드 선언 순서가 중요하다!? 큰일날 소리다! 배울 때 잘 배웠으면 좋겠다. 😮💨 그러니까 그 누군가가 말하는건 아래와 같은 내용이다.
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false, unique = true)
private String username;
- 이렇게 필드를 선언하는 순서에 따라 인덱스의 성능이 달라진다고 오해를 하더라! 아니다! 이거 때문에 이 포스팅 만들었다.
중간 정리를 하자면
그래서 복합 인덱스는 첫 컬럼이 가장 중요한 역할을 하며, 두 번째 컬럼은 첫 번째 컬럼 조건이 있을 경우에만 추가로 최적화가 된다.
두 컬럼을 동시에 사용한다는게 어떤건가요?
1. 두 컬럼을 모두 조건으로 사용하는 경우
SELECT * FROM members
WHERE username = 'john_doe' AND email = 'john@example.com';
그래서, 이런 경우에 저 복합 인덱스는 최적의 성능을 발휘할 수 있다.
복합 인덱스를 만들어 두었는데 하나의 컬럼만 검색조건으로 사용하는 경우에는 그냥 사용할까요?
거의 대부분 두가지 컬럼 모두 조건으로 사용하는데 아주 가끔 하나만 사용하는 경우엔 그 녀석을 인덱스의 첫번째 순서로 설정하고 복합 인덱스를 사용하면 될 것 같다. 근데 빈번하게 각각의 컬럼 조건으로 검색을 할 때는 단일 인덱스를 따로 만들어 두는게 더 효율적이다.
예를 들어, username, email 순으로 복합 인덱스를 설정한 경우:
- username만 조건으로 사용: username이 첫 번째 컬럼이므로 인덱스를 사용할 수 있다.
- username과 email을 모두 조건으로 사용: 복합 인덱스를 최적으로 사용할 수 있다.
- email만 조건으로 사용: username이 첫 번째 컬럼이므로, 인덱스를 사용할 수 없다. 이 경우, email 단독 조건으로 검색하는 쿼리에서 성능을 높이고 싶다면 email 필드에 별도의 단일 인덱스를 추가하는 것이 좋다.
'JPA(Java Persistence API)' 카테고리의 다른 글
[우아하게 JPA 사용] Part.2 컬렉션 조회 최적화 (0) | 2024.11.12 |
---|---|
[우아하게 JPA 사용] Part.1 지연로딩과 조회 성능 최적화 (0) | 2024.11.11 |
[JPA] Dirty Checking, Merge (8) | 2024.11.10 |
[JPA] OSIV (Open Session In View) (0) | 2023.11.16 |
[JPA] Part 18. 벌크 연산 (0) | 2023.10.30 |