Database 53

SQL - LEFT OUTER JOIN 쿼리 Split 하기!

지난번 커버링 인덱스를 적용한 쿼리를 추가 개선한 이야기이다. 커버링 인덱스 적용 - https://jaehoney.tistory.com/333 지난번 조회 Latency가 너무 커서 커버링인덱스를 조회해서 2~3배, 최대 10배 효율적으로 개선을 할 수 있었다. 문제는 Latency는 큰 문제가 없음에도 TPS가 너무 안나왔다. HTTP 트랜잭션이 0.3s~0.4s 정도인 반면 TPS가 10.8 밖에 안나왔다. 결과를 먼저 소개하자면 LeftOuterJoin 구을 Split해서 TPS를 10.8에서 107.7로 개선했다. 아래는 문제 재현을 위해 임의로 구성한 환경에서 테스트를 진행한 부분이다. 기존 코드 먼저 기존 코드를 보자. @Repository public class ArticleReposito..

Database/SQL 2024.02.27

MySQL - 인덱스를 사용해도 느린 이유! (key_len, filtered)

Optimizer가 원하는 Index를 사용했으면 최적의 쿼리인걸까?! 그렇지 않다! 예시를 통해 알아보자. 아래는 예시를 위해 생성한 Index이다. 아래의 쿼리를 실행시키면 어떻게 될까? explain select * from employees where office_id = 1 and money = 50; key로 custom_index가 선택되었다. 글자가 너무 작아서 중요한 부분을 확대했다. 실행 시간 해당 쿼리의 실행 시간은 548ms 이다. Index도 원하는 대로 탔고, 매우 간단한 데 쿼리임에도 불구하고 매우 오래걸린다. 뭐가 잘못된 걸까..? 1. key_len 다시 실행 계획을 보자. 여기서 가장 중요한 지표는 key_len이다. key_len은 쿼리 조건으로 사용된 인덱스 컬럼들의 ..

Database/SQL 2023.11.27

SQL - WHERE 절, ON 절 제대로 이해하기!

최근에 팀원 분이 LEFT OUTER JOIN의 ON 절에 일반 조건이 포함된 쿼리를 작성하신 것을 봤다. SELECT * FROM team t LEFT OUTER JOIN member m ON t.id = m.team_id AND m.team_id = 4; 해당 부분이 예상대로 동작하지 않을 것을 예상하고 리뷰를 드리면서, 생각보다 잘 모르시는 분이 많으실 것 같아 정리하게 되었다. 미리 말하지만 해당 SQL은 의도대로 동작하지 않는다. ON 절과 WHERE 절의 차이에 대해 알아보자. Sample Data 삽입 테스트를 위해 데이터를 삽입했다. Team을 5개 삽입 각 팀별 멤버를 2개 삽입 WHERE SELECT * FROM team t LEFT OUTER JOIN member m ON t.id =..

Database/SQL 2023.11.21

DB 인덱스에 대한 오해 (컬럼 1개 vs 2개!)

어느 날 신입 분이 나한테 찾아와서 물었다. '메일 조회를 할 때 권한이 없으면 404가 아니라 401 또는 403이 나와야 하는 것 아닌가요?' (인덱스 얘기한대놓고 무슨 권한 얘기인지..) 나도 쌩신입때 선배분께 동일한 질문을 했었다. 인덱스 오해 아래 코드는 비즈니스에서 Mail을 조회하기 위해 사용되던 코드이다. mailRepository.findByUserIdAndId(userId, id) .orElseThrow(() -> new EntityNotFoundException("Mail", id)); 여기서 내가 생각한 문제는 3가지가 있다. 쿼리에 비즈니스 로직이 들어간다. 가독성이 나빠지고 객체지향적인 설계가 불가능해진다. 프로그래밍 초식의 쿼리에서 로직 빼기 부분을 참고하자. 자신의 소유가 아..

Database/SQL 2023.09.16

MySQL - 이모지(Emoji) 뒷 내용이 모두 잘리는 문제 해결!

개발 DB에는 데이터가 잘 저장되는데 실 서버 DB에서 데이터가 잘리는 문제가 발생했다. 확인해보니 문자열의 이모지 뒷 내용이 전부 잘린 것으로 확인해서 DDL을 각 DB의 DDL을 비교해봤다. (MySQL을 사용하고 있다.) 그런데 개발 서버 DDL과 실서버 DDL이 동일했다. 그런데 왜 데이터가 개발 서버에서만 잘렸지..? utf8 vs utf8mb4 개발 서버와 실서버의 컬럼은 모두 charset - utf8을 사용하고 있었다. utf8과 utf8mb4는 어떤 차이가 있을까? utf8 - 내부적으로 한 문자당 가변으로 최대 3바이트를 사용한다. utf8mb4 - 내부적으로 한 문자당 가변으로 최대 4바이트를 사용한다. 여기서 이모지는 4바이트를 차지한다. 즉 utf8mb4로는 표현할 수 있고, ut..

Database/SQL 2023.04.05

Redis Cluster(레디스 클러스터) 이해하기!

해당 포스팅에서는 Redis cluster에 대해서 다룬다. Sharding 일반적으로 샤딩을 할 때 아래와 같이 Hash-Based Sharding을 사용할 수 있다. 문제는 위의 경우 샤드가 하나 늘어날 때마다 기존 데이터들을 전혀 다른 곳으로 이동시켜야 한다. Redis(레디스)는 이러한 점을 해결하고자 HashSlot을 사용한다. Redis는 16384개의 Hash Slot으로 Key 공간을 나누어서 관리한다. 각 키는 CRC16 해싱 후 16384로 Modulo Op(나머지 연산)를 하고 Hash Slot에 매핑한다. Hash slot은 각 노드들에게 나누어 분배한다. 이러한 과정으로 인해 새로운 샤드가 추가되더라도 모든 데이터가 영향을 받지 않고 Slot이 겹쳐지는 일부 샤드의 데이터만 옮겨주..

Database/NoSQL 2023.03.27

NoSQL - MongoDB 다양한 데이터 모델링 기법!

1. 너무 큰 배열 문제 아래 카페 서비스의 데이터 모델링을 한 예시가 있다. db.cafe.insertMany([ { _id: 1, name: "IT Community", desc: "A Cafe where developer's share information.", created_at: ISODate("2018-08-09"), last_article: ISODate("2022-06-01T10:56:32.00Z"), level: 5, members: [ { id: "tom93", first_name: "Tom", last_name: "Park", phone: "000-0000-1234", joined_at: ISODate("2018-09-12"), job: "DBA" }, { id: "asodsa123"..

Database/NoSQL 2023.03.21

NoSQL - MongoDB는 대용량 데이터를 처리하는 Database일까?

대용량 데이터 대용량 데이터의 기준은 뭘까? 일반적으로는 사람들이 다뤄보지 않은 데이터의 수준을 대용량 데이터라고 하는 것 같다. 그래서 회사마다 기준이 다르겠지만, 대용량 데이터의 기준은 1PB라고 말하곤 한다. MongoDB는 대용량 데이터를 위한 DB일까? MongoDB는 1PB의 데이터를 감당할 수 있을까..? MongoDB Atlas에서 어느정도 스펙까지 서버를 제공해주는 지를 보면 객관적인 수치라고 볼 수 있을 것이다. MongoDB Atlas에서 제공해주는 크기(조율이 가능) 중 가장 높은 스펙의 경우 RAM = 768GB, Storage(SSD) = 4096GB 이다. 즉 Storage는 4TB이고 기본 운영에도 스토리지가 사용된다는 것을 감안하면 300대가 있으면 1PB를 커버할 수 있다..

Database/NoSQL 2023.03.16

ElasticSearch 이해하기!

엘라스틱서치(ElasticSearch)는 Apache Lucene 기반의 Java 오픈소스 분산 검색 엔진이다. 최근 ELK 스택이라는 로그 통합 시스템에도 많이 활용하지만, 해당 포스팅에서는 엘라스틱 서치 자체에 대해서 다룬다. 활용 용도 요즘 충분한 캐시는 규모가 있는 기업이라면 당연하게 되었다. 우리가 구글, 유튜브 등에서 게시글을 조회한다고 가정하자. 검색 결과를 매번 조회하면 엄청나게 큰 부하가 발생한다. 이때 캐시를 사용할 수 있을까..? 검색에서 캐시를 활용하기는 어렵다. 캐시는 보통 Key-Value 구조를 가진다. 아래의 게시글이 있다고 가정하자. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 이때 아래와 같이 엄청나게 큰 데이터를 중복해서는 엄청나게 많은 저장 공간이 ..

Database/NoSQL 2023.02.23

MySQL - 락 불필요한 데이터를 잠그는 문제 정리! (+ Index)

락은 DBMS이나 애플리케이션에서 동시성을 제어할 수 있는 방법이다. 해당 포스팅에서는 MySQL의 락에 대해 다룬다. 락 이란? 락을 통해 동시성을 제어할 때는 락의 범위를 최소화하는 것이 중요하다. 락의 범위가 길어지면 대기중인 DB 커넥션이 많아지므로 커넥션 풀 고갈로 이어질 수 있다. MySQL에서는 트랜잭션의 커밋 혹은 롤백시점에 잠금이 풀린다. 즉, 트랜잭션이 곧 락의 범위가 된다. 트랜잭션과 락 예시를 통해 알아보자. 한 트랜잭션 내에서 DB에 Update를 하고 새로운 이미지를 업로드한다고 한다고 가정하자. 트랜잭션과 락은 각각 아래의 역할을 수행한다. 트랜잭션 업로드가 진행되는 동안에도 DB 커넥션을 유지하고 트랜잭션을 지속한다. 업로드가 성공하면 트랜잭션을 커밋한다. 업로드가 실패하면 ..

Database/SQL 2023.02.17