-
300만개의 데이터 삽입 후 index로 성능 비교대용량 데이터 & 트래픽/대용량 처리를 위한 mysql 2024. 3. 6. 20:18
public class PostFixtureFactory { public static EasyRandom get(Long memberId, LocalDate firstDate, LocalDate lastDate) { var idPredicate = named("id") .and(ofType(Long.class)) .and(inClass(Post.class)); var memberIdPredicate = named("memberId") .and(ofType(Long.class)) .and(inClass(Post.class)); var param = new EasyRandomParameters() .excludeField(idPredicate) .dateRange(firstDate, lastDate) .randomize(memberIdPredicate, () -> memberId); return new EasyRandom(param); } }
EasyRandom이라는 라이브러리를 이용해서 랜덤 값을 만드는 함수를 생성했다.
@SpringBootTest public class PostBulkInsertTest { @Autowired private PostRepository postRepository; @Test public void bulkInsert() { var easyRandom = PostFixtureFactory.get( 1L, LocalDate.of(1970, 1, 1), LocalDate.of(2022, 2, 1) ); List<Post> posts = IntStream.range(0, 2000000) .parallel() .mapToObj(i -> easyRandom.nextObject(Post.class)) .toList(); postRepository.saveAll(posts); } }
이후에 테스트 코드에서 200만개의 랜덤 데이터를 생성했다. 그리고 memberId 3번인 사용자는 100만개의 데이터를 생성하도록 했다.
이후에 데이터를 조회해봤는데 아래와 같이 5초가 넘게 걸렸다.
위와 같이 인덱스를 생성하고 인덱스를 사용했을 때의 성능을 비교해 볼 것이다.
인덱스를 사용할 때 조심해야 할 사항이 있다.
1. id의 인덱스
만약에 id 1번인 사용자가 200만개의 데이터를, id 2번인 사용자가 100만개의 데이터를 insert 했다고 가정했을 때, member_id의 index를 사용한 조회 쿼리는 속도가 더 느려진다.
그 이유는 id가 1번인 사용자는 200만개의 데이터를 가지고 있기 때문에 200만개의 데이터에 대해서 인덱스를 살펴보고 실제 데이터에도 접근하기 때문이다.
즉, 인덱스가 탐색 범위를 잘 설정하지 못했기 때문에 쿼리의 성능이 더 느려진다는 것이다.
2. created_date의 인덱스
하지만 index_created_date라는 인덱스의 성능은 엄청 빠를 것이다. 그 이유는 식별값이 크기 때문에 인덱스를 타면 접근성이 훨씬 좋기 때문이다.
3. 복합 인덱스
복합 인덱스는 컬럼 2개로 인덱스를 거는 것이다. member_id로 인덱스를 설정한 다음에 created_date로 인덱스를 설정한다.
복합 인덱스를 사용하니 0.1초라는 엄청 짧은 시간으로 단축되었다.
과일과 원산지의 인덱스를 살펴보면 왼쪽의 Banana 인덱스는 PK가 4, 5 순으로 되어있다가 오른쪽의 과일, 원산지 인덱스는 5, 4로 된다. 원산지가 China가 빠르기 때문에 이렇게 정렬된 것이다.
과일은 정렬이 되어있지만 원산지는 정렬이 되어있지 않으므로 선두 컬럼을 '과일'로 설정하는 것이 중요하다.
인덱스를 다룰 때 주의해야할 점
- 하나의 쿼리에는 하나의 인덱스만 사용하기 때문에 WHERE, ORDER BY, GROUP BY를 사용할 때는 인덱스를 잘 고려해야 한다.
- 의도대로 인덱스가 동작하지 않을 수 있으므로 explain을 확인하는 것이 중요하다.
- 인덱스도 비용이고, 쓰기/삭제를 희생하고 조회 성능을 얻는 것이다.
- 인덱스가 편하긴 하지만 인덱스로만 해결해야하는 문제인지 확인해봐야 한다.
- 데이터의 식별 정도가 높은 것으로 하는 것이 좋다. (성별같은 것은 인덱스를 안 쓰는게 좋다.)
'대용량 데이터 & 트래픽 > 대용량 처리를 위한 mysql' 카테고리의 다른 글
mysql에서 조회 최적화를 위한 인덱스 (1) 2024.03.05 대용량 시스템에 대한 이해 (0) 2024.03.03