Post

성별에 인덱스를 건다면?

남,여 인덱스

예전에 면접에서 들은 질문이기도 하고, 면접 예상 질문 목록에 보면 흔히 보이는 주제인 것 같다.

누워있다가 갑자기 생각나서 머릿속으로 실험만 하다가 한번 직접 코드를 쳐보기로 했다. 내 생각으로는 성별 단일 인덱스는 큰 효과를 보기 어려울 것 같았고, 복합 인덱스를 걸면 조금이라도 효과를 볼 수 있지 않을까 하는 궁금증에 시작하게 되었다.

예를 들어서 성별만 인덱스를 잡으면

id성별
1
2

이런 식으로 정렬될테고, 이진 탐색의 효과를 보기 어렵다고 생각했다. 오히려 인덱스 테이블을 참조하고 오는 시간이 더 걸려서 비효율적일 것이라 생각했고, 만약 성별 + 이름과 같은 복합 인덱스를 건다면 조금은 이진 탐색의 효과를 볼 수 있지 않을까 생각했다.

성별이름
Bob
David
Frank
Alice
Claire
Ellen

이런 식으로 값이 정렬될 테니까, 풀스캔보다는 빠르게 진행되지 않을까 생각했고, 코드로 테스트해보기로 했다.

실험하기

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Table(indexes = {@Index(name = "test_index",columnList = "gender or gender, name or null")})
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Builder
public class TestEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @Enumerated(EnumType.STRING)
    private Gender gender;
}


@SpringBootTest
public class DBTest {

    @Autowired
    private TestRepository testRepository;

   @Test
   void 데이터_날리기(){
       testRepository.deleteAll();
   }


    @Test
    void 데이터_주입용(){
        long size = 1000000;
        for(long i = 0; i < size; i++){
            String temp = UUID.randomUUID().toString();
            TestEntity test = TestEntity.builder()
                    .gender(Gender.values()[(int)(i % 2)])
                    .name(temp)
                    .build();
            testRepository.save(test);
        }

        for(int i = 1; i < size; i += (int) (size/ 10)){
            String name = testRepository.findById((long)i).get().getName();
            System.out.println("\""+ name + "\",");
        }
    }


    @ParameterizedTest
    @ValueSource(strings = {"99ff1cb4-f507-4f7c-8b9e-e8c1977789c2",
            "4b36b9b1-32f3-45a9-b72a-6de8a8244a38",
            "35143152-19dc-4c8d-acc6-faf41a1287a5",
            "1385729e-f986-48fe-a821-0fc32a66cd61",
            "6b15be5a-8c1a-49df-8222-a3c2a72c2765",
            "f2ce33a2-9c70-415c-b4eb-c532cecb687d",
            "f96e00a3-87d7-46bb-a07b-aad8f30dfd64",
            "638a0ccf-400f-4c63-9b4c-a93555d35f67",
            "319cd995-c61b-4fde-88c8-4d0c0f68383c",
            "451c56b9-2706-4dbd-851c-22da6ef4094a",})
    void 성별_이름(String value){
        TestEntity entity = testRepository.findByGenderAndName(Gender.MALE, value);
    }
}

100만건의 이름 샘플을 찾기가 힘들어서 이름은 UUID로 대체했다.

순서는 인덱스를 안걸고 해봤고, 성별만 인덱스를 걸어봤고, 성별 + 이름 으로 인덱스를 걸어봤다.

인덱스 X

스크린샷 2024-03-19 170720

웜업과 같은 이슈로 첫 번째 테스트 시간을 제외한다면 평균적으로 415ms 정도 걸렸다.

성별 인덱스

스크린샷 2024-03-19 170530

근소하지만 성별만 인덱스를 걸었을 때는 583ms 소요되었다.

복합 인덱스 (성별 + 이름)

스크린샷 2024-03-29 151013

평균 3.8ms가 걸렸다. 압도적으로 빠르다.

결과 분석

처음에 예상한 결과와 어느정도 맞아떨어지는 것 같다. 몇 가지 흥미로운건 잘못된 인덱스는 오히려 탐색시간을 늘리는 것을 확인할 수 있었고, 어느 정도 인덱스 구실만 할 수 있게 달아줘도 탐색 소요시간이 압도적으로 단축되는 것을 확인할 수 있었다.

참고

  • 혼자 실험
This post is licensed under CC BY 4.0 by the author.

© . Some rights reserved.

Using the Jekyll theme Chirpy