<aside> 💡 목차

</aside>

채팅 메시지에도 인덱싱을 걸자

채팅 메시지의 경우 많은 접근과 많은 데이터가 관리될 것으로 예상되기에 MySQL DB가 아닌 Mongo DB를 사용하여 구현하게 되었다.

효율적으로 DB를 접근하기 위해서 인덱싱이 필요한데, NoSQL인 Mongo DB에서도 인덱싱을 구현할 수 있었다.

<aside> ❓ 으으음 메시지를 구분할 수 있는 MessageId에만 인덱싱을 걸면 되는거 아냐?

</aside>

음, 확실히 MessageId만으로도 인덱싱의 이점이 있을 수 있다. 틀린말은 아니다. 하지만 조금 더 요구사항과 데이터베이스 접근에 대해 고민해본다면 좋은 결과를 만들 수 있다.

어떤 걸 인덱스로 걸어야 해?

MongoDB에서는 인덱싱 전략을 효율적으로 구성하기 위해 ESR 룰이 존재한다.

The ESR (Equality, Sort, Range) Rule

간단히 요약하자면 다음과 같다

<aside> 💡 ESR Rule: 어떤 document fields에 인덱싱을 걸어야할까?

  1. Equality: 정확히 검색되어야하는 필드
  2. Sort: 정렬이 필요한 필드
  3. Range: 범위 검색이 필요한 필드

를 우선으로 인덱싱을 건다.

</aside>

그렇다면 프로젝트의 트랜잭션들을 살펴보자

<aside> ⏩ 채팅 메시지 Document 접근하는 경우는 다음과 같다.

  1. 채팅 메시지 조회(Read)

    1. 특정 채팅방의 메시지를 접근하여
    2. 최신순으로 메시지를 정렬하여 100개를 가져온다.
    db.messages.find({ chatRoomId: "<채팅방ID>" })
               .sort({ timestamp: -1 })
               .limit(100);
    
  2. 채팅 요약 정보 조회(Read)

    1. 특정 채팅방의 메시지를 접근하여
    2. 최신순으로 메시지를 정렬하여 가장 마지막 메시지와
    3. 읽지 않은 메시지의 개수를 가져온다.
    // 최신 메시지 조회
    db.messages.find({ chatRoomId: "<채팅방ID>" })
               .sort({ timestamp: -1 })
               .limit(1);
    
    // 읽지 않은 메시지 수 조회
    db.messages.countDocuments({ chatRoomId: "<채팅방ID>", read: false });
    
  3. 채팅 메시지 저장(Create)

    1. 채팅메시지를 저장한다.
  4. 채팅 메시지 읽음 처리(Read, Update)

    1. 특정 채팅방의 메시지에 접근하여
    2. 읽지 않은 메시지를 찾아 읽음으로 수정한다.
    db.messages.updateMany(
        { chatRoomId: "<채팅방ID>", read: false },
        { $set: { read: true } }
    );
    

</aside>

빨간 색 글씨 부분에서 인덱싱이 필요한 필드를 유추해볼 수 있다.

  1. Equality: 특정 채팅방
  2. Sort: 시간 또는 아이디를 기준으로 정렬
  3. Range: 읽음 여부

따라서

프로젝트에서 자주 사용될 작업을 생각한다면 RoomId 와 MessageId(혹은 timeStamp) 모두 복합 인덱스로 만들어줄 필요가 있어보인다.

잠깐 그럼 Range(읽음 여부)는?

트랜잭션을 살펴본다면 읽지 않은 메시지(isRead가 false인 메시지)를 찾는 경우가 있다.