runlot

세션

기본 API는 호출마다 새 데이터베이스 세션을 사용합니다. 세션을 직접 열어야 하는 경우와 이유를 설명합니다.

기본 동작: 호출마다 새 세션

await env.db.exec("select 1");

이 한 줄은 연결, 쿼리 실행, 동기화, 연결 해제를 모두 수행합니다. 따라서 호출 사이에는 세션 상태가 남지 않습니다.

  • BEGIN은 다음 호출까지 유지되지 않습니다.
  • SET 설정은 다음 호출에 적용되지 않습니다.
  • prepared statement와 temporary table도 유지되지 않습니다.

연결을 재사용하지 않는 이유

연결을 재사용하려면 앞선 요청이 남긴 상태를 완전히 제거했다는 보장이 필요합니다. PostgreSQL의 DISCARD ALL이 그 역할을 하지만, 이 엔진에서 모든 상태를 안전하게 지우는지 아직 확인되지 않았습니다.

안전성이 확인되지 않은 상태에서 연결을 재사용하면, 한 요청의 SET 설정이나 temporary table이 다른 사용자의 요청에 영향을 줄 수 있습니다. 그래서 현재는 매번 연결을 닫고 새로 엽니다. 요청 간에 세션 상태가 전달되지 않습니다.

성능 특성

단계비용
새 세션 기본 비용2.6 ms
$1 파라미터+0.6 ms
실제 테이블 조회(카탈로그 준비)+5 ms
쓰기(커밋 + flush)+9 ms

테이블 조회의 5ms는 호출마다 새 세션을 열며 카탈로그를 준비하는 비용입니다. 안전한 세션 재사용이 확인되면 줄일 수 있습니다. PostgreSQL 프로토콜로 직접 연결해 세션을 유지하면 동일한 쿼리는 0.55ms입니다.

세션 직접 사용하기

여러 SQL 문을 같은 세션에서 실행해야 한다면 세션 핸들을 사용하세요.

const s = await env.db.session();
try {
  await s.exec("begin");
  await s.exec("insert into a values ($1)", [1]);
  await s.exec("insert into b values ($1)", [2]);
  await s.exec("commit");
} finally {
  await s.close();
}

@runlot/pg에서는 pool.connect()가 같은 역할을 합니다.

규칙

  • close()멱등입니다. 여러 번 호출해도 됩니다.
  • close()는 열려 있는 트랜잭션을 롤백합니다. 커밋하려면 직접 COMMIT을 보내야 합니다.
  • 닫힌 핸들에서 SQL을 실행하면 08003 오류가 발생합니다.
  • SQL 문을 실행하지 않은 채 30초가 지나면 세션을 회수하고 열린 트랜잭션을 롤백합니다.

요청 범위 안에서만 사용하세요

세션 핸들을 전역 변수에 저장하거나 요청 밖으로 전달하지 마세요. 30초 제한에 걸려 트랜잭션이 롤백될 수 있고, 세션을 잡고 있는 동안 다른 요청도 대기합니다.

동시 요청은 순서대로 처리됩니다

프로젝트당 데이터베이스 요청은 한 번에 하나씩 처리됩니다. 세션을 오래 유지하는 요청이 있으면 다른 요청은 대기합니다. 긴 트랜잭션은 프로젝트 전체의 응답 시간을 늘릴 수 있습니다.

SQL 문 하나의 기본 실행 제한은 10초입니다. 이를 넘는 쿼리는 중단됩니다.

이 페이지의 목차