Prisma에는 왜 JOIN이 없을까: ORM 패턴, 스키마, 내부 동작 정리

개요 Prisma로 관계형 데이터베이스를 다루다 보면 자연스럽게 드는 질문이 있음 Prisma에서는 JOIN이 어디로 갔나 하는 질문임 개발자가 작성하는 Prisma Client API에는 JOIN이 없고, 서브쿼리도 보이지 않음 정말로 없는지, 없다면 왜 그런지, 어떤 트레이드오프가 있는지 정리함 ORM이란 무엇인가 ORM은 객체와 관계형 데이터베이스 간의 매핑을 제공하는 아이디어이자 구현체 집합을 의미함 애플리케이션에서 모델을 통해 데이터베이스 테이블을 간접 제어하는 추상화 계층 제공 SQL을 직접 작성하지 않고 데이터 접근 로직을 일관된 API로 수행 가능 데이터베이스 의존성 완화 효과 기대 ...

November 23, 2025

Prisma where 관계 필터 some vs every 동작 차이와 주의점

관계형 데이터에서 Prisma의 where 절은 자식 레코드 기준으로 부모를 거르는 필터를 제공함. 특히 some과 every는 겉보기엔 비슷하지만 결과 집합을 크게 바꾸는 핵심 차이가 있음. 단일 필드만으로 필터링해도 동일하지 않을 수 있어 주의 필요 개념 some 관계된 레코드 중 적어도 하나가 조건을 만족하면 부모 포함 존재성 검사에 해당, 하나라도 매칭되면 true every 모든 관계된 레코드가 조건을 만족해야 부모 포함 단 하나라도 위배되면 제외됨 관계된 레코드가 하나도 없으면 vacuously true로 간주되어 조건 만족으로 처리됨 동작 원리 some은 존재량화, every는 전칭량화에 해당함 차이는 자식 레코드가 0개이거나 2개 이상일 때 두드러짐. 1개일 때는 조건이 동일하다면 결과가 같아질 수 있음 특히 자식이 없는 경우 every는 기본적으로 참으로 평가되어 부모가 포함됨. 빈 결과를 제외하려면 추가 조건 필요 간단 예시 model Post { id Int @id @default(autoincrement()) title String comments Comment[] } model Comment { id Int @id @default(autoincrement()) text String postId Int post Post @relation(fields: [postId], references: [id]) }댓글 text가 ‘interesting’인 항목을 기준으로 게시글을 거르는 케이스를 가정 ...

November 17, 2025

MySQL InnoDB 버퍼 풀 개념과 동작 원리, 크기 설정 가이드

개요 InnoDB 버퍼 풀은 데이터와 인덱스 페이지를 메모리에 캐싱하는 영역임 디스크 I/O를 획기적으로 줄여 지연 시간을 낮추는 게 목적임 InnoDB 스토리지 엔진(트랜잭션, MVCC, 행 단위 락 지원) 성능의 심장부라 할 수 있음 쉽게 말해, 자주 쓰는 데이터와 인덱스를 디스크 대신 메모리에 올려두고 처리하는 구조임 버퍼 풀 구성 요소 버퍼 풀에는 주로 이런 페이지(기본 16KB)가 올라옴 데이터 페이지: 실제 테이블 로우(Row)가 저장된 페이지 인덱스 페이지: B-Tree 인덱스 노드 페이지 (PK 및 세컨더리 인덱스 포함) 기타 관리 페이지: UNDO 페이지, 트랜잭션/MVCC 관리에 필요한 메타데이터 등 핵심 개념 페이지 캐싱 InnoDB는 디스크 데이터를 페이지 단위로 다룸 클라이언트가 특정 로우를 읽고 싶어 하면, 그 로우가 속한 페이지 전체를 버퍼 풀로 가져옴 이후 같은 페이지에 있는 다른 로우를 읽을 때는 디스크를 다시 보지 않고 버퍼 풀(메모리)에서 바로 조회함 ...

October 31, 2025

Prisma cursor 기반 페이지네이션 동작 원리와 skip: 1의 의미

개요 Prisma에서 cursor는 특정 레코드 지점부터 결과를 읽기 시작하는 기준점으로 동작함 skip: 1은 해당 cursor 레코드를 결과에서 제외하기 위한 옵션으로, 페이지 간 중복을 제거하는 데 사용함 핵심 동작 cursor는 그 지점부터 시작 await prisma.user.findMany({ cursor: { id: 100 }, take: 5, orderBy: { id: "asc" }, }); // 결과: 100부터 시작해 5개 반환 skip: 1은 cursor에 해당하는 레코드를 건너뜀 await prisma.user.findMany({ cursor: { id: 100 }, skip: 1, take: 5, orderBy: { id: "asc" }, }); // 결과: 101부터 5개 반환 예시로 보는 차이 데이터가 아래와 같다고 가정 ...

October 29, 2025

Prisma findMany 가이드: where, select/include, 정렬·페이징, in/비교 연산자

개요 Prisma의 findMany는 다중 레코드 조회용 메서드 기본값은 대상 모델의 모든 레코드 반환 where 필터, select/include, 정렬, 페이징, 중복 제거 등 옵션 지원 옵션 조합으로 조건 기반 조회를 간결하게 구성 가능 기본 사용법 가장 단순한 호출 형태 const users = await prisma.user.findMany();주요 옵션 옵션은 필요한 것만 선택적으로 사용 where: 조건 필터링 select: 필드 서브셋 선택 include: 관계 데이터 로드 orderBy: 정렬 기준 지정 skip, take: 오프셋 기반 페이징 distinct: 특정 필드 기준 중복 제거 where로 조건 필터링 단일 조건부터 복합 조건까지 표현 가능 ...

October 28, 2025

SQL LIMIT와 OFFSET 사용법 정리: 행 개수 제한과 페이징

기본 문법 LIMIT는 SELECT 결과에서 반환할 행 수를 제한하는 구문 WHERE와 ORDER BY 뒤, 즉 SELECT 문 끝에 위치 두 가지 형태 사용 SELECT 컬럼명 FROM 테이블명 LIMIT 개수 SELECT 컬럼명 FROM 테이블명 LIMIT 개수 OFFSET 시작_인덱스일부 dialect에서는 아래 축약형도 존재 -- MySQL, SQLite SELECT 컬럼명 FROM 테이블명 LIMIT 시작_인덱스, 개수1. LIMIT 개수 LIMIT 뒤 숫자는 인덱스가 아닌 개수 SELECT * FROM Book LIMIT 1현재 정렬 기준에서 맨 위 행 1개만 반환 ORDER BY가 없으면 반환되는 행은 비결정적일 수 있음 2. LIMIT 개수 OFFSET 시작 OFFSET은 0부터 시작 다음 예시는 4번째 행부터 1개 반환 ...

October 20, 2025