인덱스

지금껏 DB를 Jpa로 접하고, 공부도 부족해서 DB에 대해 너무 모르고 있었다.

인덱스도 이름만 들어보고 사용하면 읽기 성능이 좋아진다 라고만 알고 있었지 직접 써보질 않았기 때문에 잘 와닿지는 않았다.

이번 기회에 MySQL을 공부하면서 인덱스를 사용해서 성능 비교도 해보면서 DB에 대한 이해를 넓혀보고자 한다.


사용 기술

  • MySQL 8.4
  • DBeaver

사전 작업

아래처럼 DB에 400만 건의 데이터를 넣어뒀다.

 

데이터 형식은 아래 사진과 같다.

memberId = 1에 해당하는 데이터는 300만건, memberId = 2에 해당하는 데이터는 100만건이다.

  • 날짜는 5월 26~ 27일 사이의 랜덤 값
  • memberId = 1 또는 2이다.
  • content는 랜덤한 값

 

이 데이터들을 이용하여 인덱스 사용 전/후의 성능을 비교해볼 것이다.


1. 인덱스 사용 전 

인덱스를 사용했을때와 비교해보기 위해 대조군으로 측정한다.

1-1. 실행 계획 분석

MySQL의 EXPLAIN 을 이용하여 실행 계획을 분석한 결과는 아래와 같다.

인덱스 없이 탐색한 rows가 거의 400만 개로 풀 스캔한 결과인듯 하다.

1-2. 쿼리 시간

400만 건의 데이터를 조회하는데 18초가 걸렸다.

1-3. CPU 점유율

400만건의 데이터를 조회하기 위해 CPU 점유율이 27%까지 올라갔다.


2. 인덱스 추가

이제 인덱스를 추가해보자.

SQL로 생성해도 되고, DBeaver 같은 GUI를 써서 추가해줘도 된다.

본인은 아래처럼 GUI로 3개의 인덱스를 추가해줬다.

  • createdDate 인덱스
  • memberId 인덱스
  • createdDate, memberId 복합 인덱스

 

인덱스 생성 결과는 아래처럼 확인할 수 있다.

이 인덱스


3. memberId 인덱스 사용

3-1. 실행 계획 분석

3-2. 쿼리 시간

24초로 인덱스를 타지 않은 쿼리보다 느린 결과를 얻었다.

3-3. CPU 점유율

인덱스를 타지 않은 쿼리보다 더 높은 CPU 점유율을 기록했다.

3-4. 결과 분석

인덱스를 걸었음에도 불구하고 쿼리 시간이 더 느려졌다.

이유를 찾아보자면 인덱스를 탔음에도 탐색 범위를 많이 줄이지 못했기 때문에 인덱스 테이블도 확인하고,

Post 테이블의 데이터까지 확인해야 했기 때문에 인덱스 없이 테이블 풀 스캔을 한 결과보다 느리게 나왔다고 볼 수 있다.

 

참고로 memberId = 2로 쿼리를 날려보면 아래처럼 쿼리 속도가 8초로 개선됐음을 확인할 수 있다.

이를 통해 쿼리에 해당하는 데이터 분포도에 따라서 쿼리 속도가 더 느려질 수 있다는걸 알았다.


4. createdDate 인덱스 사용

4-1. 실행 계획 분석

rows 만 보면 인덱스를 사용하지 않았을 때와 큰 차이가 없다.

하지만 type이 all 이냐, index에 따라 효율이 달라지는듯 하다.

4-2. 쿼리 시간

인덱스를 타지 않은 쿼리보다 훨씬 빠른 조회 결과를 얻었다.

4-3. CPU 점유율

쿼리가 너무 빠르게 실행돼서 CPU 점유율 변동이 없었다.

거의 0.1% 정도라고 생각하면 될것 같다.

4-4. 결과 분석

createdDate는 데이터 분포가 골고루 되어 있어서 그런지 인덱스를 타면 조회 성능이 훨씬 개선됨을 알 수 있었다.

rows가 커서 조회 속도가 느리지 않을까 생각했는데 데이터 분포가 엄청 큰 영향을 미치는가 보다.


5. createdDate, memberId 복합 인덱스 사용

5-1. 실행 계획 분석

rows가 createdDate 단일 인덱스보다 더 적어졌다.

5-2. 쿼리 시간

createdDate 단일 인덱스 보다 더 빠른 조회 결과를 얻었다.

5-3. CPU 점유율

쿼리가 너무 빠르게 실행돼서 CPU 점유율 변동이 없었다.

여기서도 거의 0.1% 정도라고 생각하면 될것 같다.

5-4. 결과 분석

18초 걸리던 쿼리가 0.002초로 엄청난 조회 속도 개선이 되었다.

복합 인덱스를 잘 이용하면 단일 인덱스를 이용하는것 보다 더 좋은 조회 결과를 얻을 수 있는걸 알 수 있었다.

복합 인덱스는 인덱스 순서에도 영향을 받는다고 하니 잘 이용하기 위한 조건을 확인해서 잘 쓸 수 있도록 해야겠다.


6. 정리

특정 인덱스에 따라 성능이 좌우 되는건 아니고 데이터의 분포도에 따라 성능이 달라질 수 있음을 알았다.

인덱스를 사용하면 항상 성능이 좋아지는건 아니고 오히려 나빠질 수 있다는것도 알 수 있었다.

인덱스를 사용하기 위해 주의해야할 점과 더 효율적으로 쓸 수 있는 방법을 더 공부해봐야 할것 같다.

 

참고로 위에서 실험할때는 use index로 인덱스를 설정했다.

use index를 제거하면 아래처럼 MySQL 내부에서 최적화하여 인덱스를 타서 쿼리를 실행한다.

하지만 최적화 결과가 항상 최선은 아니기 때문에 EXPLAIN으로 자주 확인하는게 좋을듯 하다.

'데이터베이스' 카테고리의 다른 글

Redis 써보기  (0) 2024.04.17
[DB] DML, DDL, DCL 이란?  (0) 2023.10.01

Redis

레디스는 인메모리 기반의 NoSQL 데이터베이스이다.

지금껏 괜히 레디스라고 하면 괜히 쓰기 힘들것 같아서 미뤄뒀었다.

그러다가 안해본것들 하나씩 해보기의 일환으로 이번에는 레디스를 써보기로 했다.


Redis 설치

레디스를 쓰려면 우선 EC2든 로컬이든 레디스가 깔려있어야 한다.

인텔리제이 얼티밋 버전은 따로 DB 연결을 관리하는지는 모르겠지만 본인은 흙수저 버전이므로 직접 설치한다.

맥에서는 아마 brew로 다운 받지 않을까 싶은데 윈도우에서는 직접 설치했다.

윈도우 환경에서 레디스를 설치하려면 아래 링크에서 원하는 버전의 msi 확장자로 다운받고 설치한다.

본인은 윈도우 10을 쓰고 있고 Redis는 대충 최신 버전으로 했음(3.0.504)

https://github.com/microsoftarchive/redis/releases

msi 파일 실행하고 설치는 꽤 직관적이므로 설치 과정은 생략한다.

설치가 완료 됐으면 아래처럼 작업 관리자에서 실행중인지 확인할 수 있다.


Redis 사용

윈도우에서는 redis-cli.exe를 사용해서 레디스 상태를 확인할 수 있다.

위에서 설치한 레디스 경로로 가보면 redis-cli.exe가 있을것이다.

redis-cli에 ping을 입력하면 pong으로 응답이 오면 제대로 연결된것이다.

레디스의 기본 포트번호는 6379이다.

만약 이 포트번호를 바꿔서 사용하고 싶다면 redis.windows.conf 설정을 바꾸면 된다.

레디스 데이터베이스 선택하기

기본적으로 0~15의 instance가 떠있으며, 각각의 인스턴스에 데이터를 따로 저장할 수 있다.

아래 커맨드로 데이터베이스를 선택할 수 있다

SELECT 번호 // 기본 값은 0

 

아래처럼 cli 입력부분에서 몇번째 데이터베이스를 쓰는지 확인할 수 있다.

레디스에 데이터 읽기/쓰기

redis-cli에 아래와 같은 커맨드로 입력하면 key, value 형태로 저장된다.

커맨드가 성공하면 OK라는 응답값을 준다.

SET key value

 

redis-cli에 아래와 같은 커맨드로 입력하면 key에 해당하는 value 값이 출력된다.

만약 key에 해당하는 데이터가 없을 때에는 (nil)이라는 응답을 반환한다.

GET key

 

직접 redis-cli로 써보면 아래와 같이 확인할 수 있다.

레디스에 저장된 데이터 삭제하기

redis-cli에 아래처럼 커맨드를 입력하면 key에 해당하는 데이터들이 삭제된다.

삭제에 성공하면 (interger) 1 이라는 값을 반환하고, 실패하면 (integer) 0이라는 값을 반환한다.

DEL key1 key2 key3

 

위 읽기/쓰기에서 이어서 redis-cli를 써서 해보면 아래와 같이 확인할 수 있다.

  • 처음 hi에 해당하는 값을 지울때는 저장된 데이터가 있었으므로 (integer) 1을 반환
  • 이후 조회 시 저장된 데이터가 없으니 (nil) 반환
  • 다시 hi에 해당하는 값을 지울때는 저장된 데이터가 없으므로 0 반환

레디스에 저장된 모든 데이터 삭제하기

테스트코드를 돌릴 때 이상적인 테스트 환경을 보장하기 위해 각각의 테스트 전후로 DB를 비워둔다.

이럴 때 사용하는 레디스 커맨드는 아래와 같다.

FLUSHDB   // 현재 선택한 데이터베이스의 데이터 삭제
FLUSHALL  // 모든 데이터베이스의 데이터 삭제

 

'데이터베이스' 카테고리의 다른 글

MySQL에서 인덱스 사용 후 성능 비교  (0) 2024.05.27
[DB] DML, DDL, DCL 이란?  (0) 2023.10.01

DML, DDL, DCL, TCL

새로 표를 만들어서 정리하고 싶었지만 티스토리 표 만지기 너무 힘들어서 잘 정리된 표가 있길래 퍼왔다. 

텍스트가 필요할 경우 아래 원본 링크를 참고하자.

 

 

 

출처)

 

[DB] DDL, DML, DCL 이란?

명령어 종류 명령어 설명 데이터 조작어(DML : Data Manipulation LanguageSELECT 데이터베이스에 들어 있는 데이터를 조회하거나 검색하기 위한 명령어를 말하는 것으로 RETRIEVE 라고도 함INSERTUPDATEDELETE 데

brownbears.tistory.com

 

'데이터베이스' 카테고리의 다른 글

MySQL에서 인덱스 사용 후 성능 비교  (0) 2024.05.27
Redis 써보기  (0) 2024.04.17

+ Recent posts