전체 글 333

대용량 쿼리 벌크 업데이트

그동안 잘못 알고 있었던 사실.DB에 최소한으로 접근하는 것이 항상 좋다.-> DB에 연결된 트랜잭션의 시간이 길어진다면, 전체적인 데이터베이스의 접근하는 속도가 저하된다. 사실 위 의미대로라면 분할로 업데이트하는 청크는 설명될 수 없다.NestJS, MySQL, Typeorm의 예를 들어보겠다. 1. 업데이트에 필요한 행만큼 쿼리문 실행async bulkMap(dto: BulkDto): Promise { let updatedCount: number = 0; await this.entityManager.transaction(async (em) => { for(const item of dto.items){ const result = await em..createQueryB..

Server/성능개선 2026.02.19

2025년 회고

조금은 늦었지만 2025년 회고를 작성해본다. 25년도에 맞이한 가장 큰 변화는 이직이다.그동안 30인 이하의 스타트업에서만 근무를 했었고, 25년 7월에 총 사원수 300명에 육박하는 기업에 입사했다.내가 속한 팀의 팀원은 20명 정도였고, 개발파트 인원은 나 포함 3명이다.작은 기업에서도 항상 개발팀의 인원은 많았고, 입지가 두터웠다면 현재의 회사에서는 그와 정반대의 느낌이다. 이직 하위의 가장 큰 변화는 세 가지가 존재한다. 1. 내가 만든 제품을 사용하는 사용자가 존재한다.여러 회사를 거치면서 많은 프로젝트를 진행했지만 항상 사용자는 거의 존재하지 않았다.어떤 문제점이 있을까, 어떻게 해결해야될까는 늘 추상적이고 글로만 접했으며 개인프로젝트에서만 해결했었던 사건들이었다.지금은 라이브 로그를 가만히..

생각정리 2026.01.09

Next 14 & React 18) 빌드에러

오랜만에 넥스트를 돌렸는데 이상한 에러가 발생해서 해결하는데 이틀이나 소요됐다.Error: should not be imported outside of pages/_document.TypeError: Cannot read properties of null (reading 'useState')Error occurred prerendering page "/_not-found".Export encountered an error on /_not-found/page: /_not-found, exiting the build. 이외에 여러 에러도 만나봤지만, 해결했던 결론만 먼저 이야기하고 시작하겠다. 나의 경우 아래를 확인하니 해결됐다.echo $NODE_ENV# development 진행중인 백엔드 프로젝트에서..

Client/Next.js 2025.12.31

JS & TS) Map으로 시간복잡도 줄이기

C++에서는 map, set을 엄청 자주 사용했는데,JS에서는 이상하게 사용을 안하게 된다.그러다 반복문에서 include, find 등 람다식을 사용해 이중포문을 만들게 되었고. 5만건의 유저 업데이트 중, O(n2)이라는 무시무시한 경험을 해버렸다.그래서 부랴부랴 C++에서 사용했던 맵을 다시 사용했다. const users: User[] = await this.userRepo.find();// new Mapconst userMap: Map = new Map(users.map((u) => [u.id, u]));// hasif(userMap.has(1)) console.log('id 1인 유저 포함');// getconst user1 = userMap.get(1);// setuserMap.set(2,{..

Server/성능개선 2025.12.10

평균 15s API 응답속도 2s로 줄이기

문제상황모든 구매목록을 가져오는 API가 있다.총 구매목록은 2만여건이지만, 조인된 테이블들의 데이터 가짓수를 합치면 60만여건이 넘었다.DTO를 활용하여 모든 테이블을 조인하고 테이블별 검색조건을 where절로 한 번에 검색할 수 있는 편리함이 있었지만, 검색을 하지 않아도 되는 상태에서도 모든 테이블을 조인하는 문제가 있었다.그래서 해당 페이지에 진입하면 모든 구매목록을 가져오기 때문에 15초라는 긴 시간이 소요됐다. 해결방법리스트 페이지는 디테일 정보를 표기할 필요가 없으므로, 필요없는 테이블은 조인에서 제외한다.DTO에 따라 검색조건이 들어오면, 필요한 테이블만 조인한다.인덱스를 탈 수 없는 LIKE 검색은 최소화한다.검색조건으로 사용되는 컬럼들은 인덱싱을 설정한다. 사이드 이펙트해당 API에서 ..

Server/성능개선 2025.10.17

MySQL, TypeORM) Lock으로 동시성 문제 해결

전제조건product 테이블에는 stock이라는 재고가 있다.재고는 0이 되면 구매할 수 없다.a, b 유저가 동시에 동일한 상품을 구매한다. 로직 a, b유저는 재고가 존재하는 상품의 정보를 불러온다.SELECT * FROM product WHERE id = 1 AND stock > 0; 문제 상황a가 먼저 상품을 구매하고 재고를 차감하여 재고가 0이 되면, b는 불러왔던 상품을 구매할 수 없다.트랜잭션을 사용했지만 두 유저가 동시에 테이블에 접근하는건 막을 수 없었다. 해결 방법상품을 읽을 때 부터 Lock을 걸어 해당 행을 다른 유저가 가져올 수 없게 만든다.Lock을 건 상황에서 에러가 발생했다면, 빠르게 락을 해제해야한다. 무한히 기다리는 데드락이 발생할 수 있기 때문.SELECT * FROM ..

Server/성능개선 2025.10.17

NestJS) AWS-S3 효율적인 업로드 방법

배경회원가입시 이미지를 s3에 업로드한다.방법 1프론트에서 이미지를 인풋태그에 삽입하면, 블롭으로 이미지를 만들어 미리보기를 만든다.서버에 formData로 바로 전송해 하나의 API에서 검증 및 S3업로드, 다른 로직을 수행한다. 장점하나의 API에서 작업하니 편리하다 단점바디를 formData로 받아야한다.스웨거 작성 등 직접 나열해야 하는 이유로 불편하다.방법 2프론트에서 이미지를 인풋태그에 삽입 시, API를 한 번 호출한다.API에서는 getSignedUrlPromise 함수로 만료시간이 존재하는 임시 이미지를 버킷에 생성한다.해당 url과 파일 정보를 받아 프론트에서 이미지 태그로 미리보기를 만든다.서버에 json 바디로 파일정보를 가입할 회원의 정보와 함께 송신한다.서버에서는 회원 검증을 마..

Server/성능개선 2025.08.07

NestJS) 의존성주입에서 객체 초기화 문제

먼저 백그라운드를 정해본다. 1. AppModule에 임포트 순서대로 모듈의 초기화가 진행된다.import { Module } from '@nestjs/common';import { TypeOrmModule } from '@nestjs/typeorm';import { AppController } from './app.controller';import { AppService } from './app.service';import { EnvConfigModule, TypeOrmConfigService,} from './config';import { AuthModule } from './modules/auth/auth.module';import { AdminModule } from './modules/adm..

Git) 계정 2개 같은 호스트로 사용하기

https://juzdalua.tistory.com/5 Git 여러 계정 사용하기회사계정, 개인계정을 하나의 컴퓨터에서 사용하다보면 repository에 접근하기가 어려워진다.이를 위한 해결책은 bash에서 ssh key를 이용한 방법이 있다. 1. rsa 키 만들기ssh-keygen -t rsa -C "깃헙계정@emjuzdalua.tistory.com 위 글은 2달차 신입이 작성한 글이라 지금 다시 봐도 어지럽다.그래서 다시 작성한다. 먼저 깃 계정 2개가 필요하다. 회사계정 1개, 개인 계정 1개라 가정한다.계정1: a@a.a계정2: b@b.b 각각 키를 만들고, 각 계정의 Git ssh 정보를 입력한다.ssh키의 정보는 .pub 파일이 아닌 확장자가 명시되지 않은 파일의 내용을 전부 복사하면 된다...

Settings/Git 2025.08.01