Skip to content

Proxy객체를 사용해 쿼리횟수 줄이기

이민수 edited this page Nov 4, 2024 · 2 revisions

👀 Proxy객체를 사용해 쿼리횟수 줄이기

개요

채팅 기능을 개발하던 도중 메세지를 보낼때 마다 chatRoom을 조회하고 chatMessage를 삽입하는 2번의 쿼리가 발생했습니다.

특히 채팅 메세지는 자주발생하는 이벤트 인 만큼 메세지를 보낼때 마다 2번의 쿼리가 발생한다는 점에서 개선이 필요하다 생각이들었습니다.

고민

@Transactional
    public ChatMessageDTO createChat(Long roomId, ChatMessageDTO dto){

        ChatRoom room = chatRoomRepository.findById(roomId).orElseThrow(()->new IllegalArgumentException("채팅방이 없습니다"));
        ChatMessage message = ChatMessage.builder()
                .sender(dto.getSender())
                .message(dto.getMessage())
                .room(room)
                .sendTime(dto.getSendTime())
                .build();
        chatMessageRepository.save(message);
        return dto;
    }

ChatMessage를 보낼때 ChatRoom을 조회 하는 이유는

1, ChatMessage 객체는 해당 메시지가 어느 채팅방에서 보낸 것인지를 알아야 하므로,

room 필드를 통해 ChatRoom 엔티티를 참조하게 됩니다. 이 필드를 통해 ChatMessageChatRoom 간의 관계를 명시적으로 설정해야 하며,

2, ChatRoom객체가 없을시 발생하는 참조 무결성 문제 때문에 메세지를 보낼때마다 ChatRoom을 조회한다는 점

이러한 이유로 인해 ChatRoom을 조회해야합니다.

해결 방법

1, 어느 채팅방에서 보낸 것인지를 알아야 한다는 점에서 → 프록시 객체 사용

프록시 객체를 사용하면, 실제 ChatRoom 데이터를 즉시 조회하지 않고도 ChatRoom과의 관계를 설정할 수 있습니다.

2, 참조 무결성을 유지하기 위해 → 데이터베이스 레벨에서 제약 조건으로 검증

데이터베이스에서 참조 무결성을 유지하기 위해, 외래 키 제약 조건을 사용하여 ChatRoom이 존재하는지 검증합니다.

이렇게 하면, 데이터베이스는 ChatRoom이 존재하지 않으면 메시지를 저장할 수 없도록 보장합니다.

특히, 프록시 객체를 사용할 경우 채팅방에 대한 추가 조회 쿼리를 실행하지 않게 되어 성능을 최적화할 수 있다는 점에서 이 방식을 선택했습니다.

구현 방법

1,먼저 EntityManager를 빈으로 등록합니다.

@Autowired
    private EntityManager entityManager;

2,이후, getReference 메서드를 사용하여 ChatRoom에 대한 프록시 객체를 조회합니다

ChatRoom room = entityManager.getReference(ChatRoom.class, roomId);

3,이렇게 조회된 프록시 객체를 ChatMessage 객체의 room 필드에 참조시킵니다

ChatMessage message = ChatMessage.builder()
                .sender(dto.getSender())
                .message(dto.getMessage())
                .room(room)
                .sendTime(dto.getSendTime())
                .build();

데이터베이스 레벨에서 제약 조건으로 검증

프록시 객체를 사용 했을때 문제점을 고민한 결과

ChatRoom은 DB에서 조회하는것이 아닌 프록시 객체를 사용하는 것이므로 참조무결성이 보장되지 않는다는 점 이였습니다,

그래서 DB레벨에서 제약조건으로 검증했습니다.

ALTER TABLE chat_message
ADD CONSTRAINT fk_room_id
FOREIGN KEY (room_id) REFERENCES room(id) ON DELETE CASCADE;

이렇게 프록시 객체를 활용해 불필요한 데이터베이스 쿼리 실행을 줄이고, 참조 무결성은 데이터베이스에서 관리하도록 최적화하였습니다.

테스트

프록시 객체를 사용하기전

프록시 객체 사용전 채팅메세지 보낼때마다 쿼리 2번

프록시 객체를 사용한 후

프록시 객체로 쿼리횟수 1회로

예상대로 결과가 2회에서 1회최적화가 되었습니다.