💡발단 HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory WARN이 반복적으로 나오는 걸 보게 됐다. 이때까지만 해도 ERROR은 아니니까 적당히 나중에 리팩토링해야겠다고 생각했다. 그러나 쿼리문을 자세히 보니 큰 문제가 있다는걸 깨달았다. 실제 쿼리를 날릴 때 limit 을 걸지 않는다. 알고보니 DB에서 모든 row를 가져온 뒤에 메모리상에 올려두고 처리하는 방식이었다. 아래는 Querydsl 코드. location_bookmark는 location에 대한 일대다 엔티티이다. location_bookmark를 레프트 조인하고 fetch join하면서 발생하는 부분이 핵심이다. public JPA..
💡발단 프로젝트의 필수 구현이 마무리되고, 리팩토링을 하면서 쿼리를 최적화할 일이 생겼습니다. 경험적으로, 감으로 하기보다는 체계적으로 최적화할 방법을 고민하던중에 EXPLAIN(쿼리 실행 계획 분석)을 알게 되었습니다. 그 과정에서 EXPLAIN을 공부하게 된 내용을 서술합니다. EXPLAIN 🤔 그게 뭔데? MySQL에서는 최적의 쿼리를 실행하기 위해 각 테이블의 데이터가 어떤 분포로 저장되어 있는지를 참조하고, 해당 데이터를 기반으로 최적의 실행 계획을 수립해주는 쿼리 옵티마이저가 내부적으로 동작한다. EXPLAIN이란 여기서 MySQL 옵티마이저가 생성하는 실행 계획을 테이블(엑셀에 가까운) 형태로 볼 수 있게 하는 명령이다. 사용 방법 간단하다. SQL 앞에 EXPLAIN을 명령을 넣고 실행하면..
프로세스에 대해 설명해주세요. : 운영체제로부터 메모리 공간을 할당 받아 실행중인 프로그램을 의미합니다. 프로세스의 특징 프로세스들은 서로 독립된 메모리 공간을 가지므로, 프로세스끼리는 임의로 서로의 영역에 접근할 수 없습니다. IPC(inter process communication)를 통해 프로세스간에 통신할 수 있다. 프로세스는 운영체제 커널에 의해 관리됩니다. 커널은 프로세스를 위해 사용자 공간에 메모리를 할당하고, 프로세스 ID를 부여하며, 프로세스 테이블을 이용하여 생성된 모든 프로세스의 정보를 관리합니다. 프로그램에 대해 설명해주세요. : 하드 디스크나 USB 등 저장장치에 저장된 실행 가능한 파일입니다. 프로세스의 메모리 공간에 대해 설명해주세요. : 프로세스는 4개의 메모리 영역으로 구성..
💡 발단 발단 부분은 Java적인 문제이고, 본론은 이 다음에 나오니 건너뛰시길 추천드립니다. 프로젝트를 진행하다가 엔티티 생성자쪽에서 에러가 발생했다. Builder 생성자에서 엔티티 컬렉션 필드를 할당하는 쪽에서 생긴 문제인데, 너무 당연하게 생각했어서 더 많은 생각을 하게 됐다. Spring 프로젝트를 2번 하는 동안 컬렉션 필드를 생성자에서 만들어본 적이 없었던 것. 상황은 이렇다. 컬렉션 필드를 addAll()로 할당하는 부분에서 NPE(Null Pointer Exception)가 발생한 것. 문제는 NULL값이 들어갈 때였다. // ... 필드 private List feedImages = new ArrayList(); @Builder private Feed(String title, Strin..
운영체제 면접 질문에 답변하기 위해 공부한 내용들을 기록합니다. 여러가지 개념에 대해 면접식 흐름으로 서술했습니다. 붉은색 글씨의 내용은 핵심 답변이고 밑의 내용은 꼬리 질문에 대한 답변입니다. 모의면접을 진행하면서 부족한 점들은 보충할 예정입니다. 질문 출처는 jscode이며 답변 출처는 하단에 정리해놓았습니다. 공부한 내용들 운영체제는 무엇이고 어떤 역할을 수행하는지 설명해주세요. 운영체제란? : 컴퓨터 사용자와 컴퓨터 하드웨어 사이의 중개자(intermediary) 역할을 하는 시스템 소프트웨어 (시스템 소프트웨어 : 응용 프로그램과 하드웨어 장치 사이에 존재하는 소프트웨어를 통칭하는 용어로, 운영체제와 컴파일러 등이 있음.) 운영체제의 구성요소 : 커널(운영체제의 핵심 코드), UI 및 도구 프로..
JOIN이란? : 원하는 데이터가 둘 이상의 릴레이션에 흩어져 있는 경우, 관련 튜플들을 조합하여 하나의 릴레이션(테이블)을 구성하도록 하는 검색(SELECT) 방법. 조인은 릴레이션들의 공통 속성을 기준으로 하므로 테이블들간에 최소한 하나의 속성을 공유하고 있어야 한다. 여러가지 조인 조건에 따라 검색 결과를 다르게 할 수 있다. 아래는 뒤에서 예시로 들 과목, 수강 테이블. 과목번호 과목명 강의 교수 001 컴퓨터구조 장성태 002 정보보호개론 양수미 003 디지털논리설계 장성태 004 네트워크보안 양수미 학번 과목번호 학점 180 001 B 181 002 B+ 180 003 A+ 181 004 A 크로스 조인(CROSS JOIN) 테이블 행들 사이의 모든 조합을 행으로 갖는 하나의 통합 테이블을 만..
💡발단 우리 프로젝트의 프론트엔드는 모바일 안드로이드로, 대부분의 조회 페이지가 무한 스크롤로 구현된다. 즉, 오프셋이 쓰이지 않고 커서를 이용해 페이징한다. 마지막으로 응답했던 레코드의 id 값을 커서(커서 아이디)로 사용한다. 맨 처음엔 커서 아이디를 0으로 요청 -> 아이디 1~10을 갖는 레코드를 응답하고, 그 다음엔 커서 아이디를 10으로 요청 -> 아이디 11~20 을 갖는 레코드를 응답하는 식이다. 이 상황에서 조회 기능들을 구현하면서 배우게 된 Page의 단점과 Slice의 장점을 서술하고자 한다. ❗Page, Pageable의 대부분의 필드는 커서 페이징에 필요하지 않다. 애초에 커서 페이징에는 offset이 쓰이지 않는다. offset이 없으므로 getOffset, getPageNumb..
데이터 이상과 정규화를 공부하는 과정을 정리합니다. "누가 DB 설계를 저렇게 해~?" 라고 생각하기도 했지만, 관계형 데이터베이스에서 중복성과 무결성을 강조하는 이유를 이해햐기 좋은 계기가 되었습니다. 💡 데이터 이상(data anomaly) 데이터 이상은 잘못된 DB 설계 과정에서 불필요한 데이터 중복으로 인해 발생하는 부작용을 말한다. 먼저 아무 생각 없이 릴레이션을 짰을 때 무슨 문제가 생기는지 알아보자. 여기 Student 릴레이션이 있다. 학번(PK) 이름 학과 위치 나이 170 원석 컴퓨터 304호 27 180 영두 컴퓨터 304호 24 얼핏 보면 별 문제 없어보이고 검색(SELECT)까지만 해도 전혀 문제가 없다. 그러나 삽입, 갱신, 삭제시에 치명적인 문제가 발생한다. 삽입 이상 : 불필..
기획 단계 혹은 요구사항 분석 단계에서 API 명세, 와이어프레임 작업, 컨벤션 확립 등의 과정을 거친다. 예를 들어 회원 이름의 글자 수 제한은 기획 단계에서 정해진다. 이러한 값들을 초기에 상수화하여 관리하면 관심사를 분리할 수 있고 개발이 편해진다. 추후 기획이 변경되더라도 다른 파일들의 git 변경 이력을 최소화할 수 있다는 장점도 있다. 와이어프레임의 정보를 상수화하기 아래 사진은 피그마로 디자인된 게시글 작성 페이지. 극초기의 와이어프레임이었다. public final class ConstraintConstants { public static final int SPOT_IMAGE_MAX_SIZE = 5; public static final int SPOT_CONTENT_MAX_LENGTH = ..
상황 설명 현재 프로젝트에는 환경 퀴즈를 푸는 서비스가 있고, 유저가 제출한 퀴즈를 복습하는 기능이 있다. 특이한 점은 복습 퀴즈들을 랜덤으로 보여줘야 한다는 것. 즉 문제들의 정렬 방식을 랜덤으로 두어서 유저가 요청할 때마다 다른 퀴즈를 봐야한다. 발단 문제는 랜덤 정렬을 구현하면서 발생했다. @Override public Slice findRecentQuizzes(Long userId, int limit) { JPAQuery query = queryFactory.selectFrom(quiz) .where(...) .orderBy(NumberExpression.random().asc()) // 이 부분 // ... } 발생한 에러: org.springframework.dao.InvalidDataAcce..