주요 변경 사항
중첩 관계 필터링 지원 중단
0.28.0
버전부터는 아래 예제가 동작하지 않습니다:
const usersWithPosts = await db.query.users.findMany({
where: (table, { sql }) => (sql`json_array_length(${table.posts}) > 0`),
with: {
posts: true,
},
});
where
콜백 내의 table
객체는 더 이상 with
와 extras
로부터 필드를 포함하지 않습니다. 이를 제거함으로써 더 효율적인 관계형 쿼리를 구축할 수 있게 되었고, 이는 행 읽기와 성능을 개선했습니다.
이전에 where
콜백에서 해당 필드를 사용했다면, 다음과 같은 해결 방법을 고려할 수 있습니다:
- 행을 가져온 후 코드 레벨에서 필터를 직접 적용하기
- 코어 API 사용하기
mysql2
드라이버에 관계형 쿼리 mode
설정 추가
Drizzle의 관계형 쿼리는 항상 하나의 SQL 문을 생성하여 데이터베이스에서 실행합니다. 하지만 이 방식에는 몇 가지 주의사항이 있습니다. 모든 데이터베이스에 최적의 지원을 제공하기 위해 모드 설정을 도입했습니다.
Drizzle의 관계형 쿼리는 내부적으로 서브쿼리의 Lateral Join을 사용합니다. 현재 PlanetScale은 이 기능을 지원하지 않습니다.
- 일반 MySQL 데이터베이스에서
mysql2
드라이버를 사용할 때는mode: "default"
를 지정해야 합니다. - PlanetScale에서
mysql2
드라이버를 사용할 때는mode: "planetscale"
을 지정해야 합니다.
import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';
import * as schema from './schema';
const client = await mysql.createConnection({
uri: process.env.PLANETSCALE_DATABASE_URL,
});
const db = drizzle({ client, schema, mode: 'planetscale' });
대규모 스키마에서 IntelliSense 성능 개선
85개의 테이블, 666개의 컬럼, 26개의 열거형, 172개의 인덱스, 133개의 외래 키로 구성된 데이터베이스 스키마에 대해 진단을 수행했습니다. 내부 타입을 최적화하여 IntelliSense 속도가 430% 빨라졌습니다.
관계형 쿼리 성능 및 읽기 사용성 개선
이번 릴리스에서는 관계형 쿼리 API를 위한 쿼리 생성 방식을 완전히 변경했습니다. 주요 변경 사항은 다음과 같습니다:
-
Lateral 조인: 새 버전에서는 “LEFT JOIN LATERAL” 절을 사용하여 관련 테이블에서 특정 데이터를 효율적으로 가져옵니다. MySQL(PlanetScale)과 SQLite에서는 간단한 서브쿼리 선택을 사용하여 쿼리 계획과 전반적인 성능을 개선했습니다.
-
선택적 데이터 검색: 새 버전에서는 테이블에서 필요한 데이터만 검색합니다. 이렇게 특정 데이터만 가져오면 불필요한 정보를 줄여 처리할 데이터셋이 작아지고 실행 속도가 빨라집니다.
-
집계 함수 감소: 새 버전에서는 집계 함수(예: COUNT, json_agg)의 수를 줄였습니다. Lateral 조인 내에서 json_build_array를 직접 사용하여 데이터를 더 효율적으로 집계함으로써 쿼리 성능을 개선했습니다.
-
단순화된 그룹화: 새 버전에서는 GROUP BY 절을 제거했습니다. Lateral 조인과 서브쿼리가 이미 데이터 집계를 더 효율적으로 처리하기 때문입니다.
다음은 Drizzle 쿼리 예제입니다:
const items = await db.query.comments.findMany({
limit,
orderBy: comments.id,
with: {
user: {
columns: { name: true },
},
post: {
columns: { title: true },
with: {
user: {
columns: { name: true },
},
},
},
},
});
새로 생성된 쿼리:
SELECT "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content",
"comments_user"."data" AS "user",
"comments_post"."data" AS "post"
FROM "comments"
LEFT JOIN LATERAL (
SELECT json_build_array("comments_user"."name") AS "data"
FROM (
SELECT *
FROM "users" "comments_user"
WHERE "comments_user"."id" = "comments"."user_id"
LIMIT 1
) "comments_user"
) "comments_user" ON true
LEFT JOIN LATERAL (
SELECT json_build_array("comments_post"."title", "comments_post_user"."data") AS "data"
FROM (
SELECT *
FROM "posts" "comments_post"
WHERE "comments_post"."id" = "comments"."post_id"
LIMIT 1
) "comments_post"
LEFT JOIN LATERAL (
SELECT json_build_array("comments_post_user"."name") AS "data"
FROM (
SELECT *
FROM "users" "comments_post_user"
WHERE "comments_post_user"."id" = "comments_post"."user_id"
LIMIT 1
) "comments_post_user"
) "comments_post_user" ON true
) "comments_post" ON true
ORDER BY "comments"."id"
LIMIT 1
이전에 생성된 쿼리:
SELECT "id",
"user_id",
"post_id",
"content",
"user"::JSON,
"post"::JSON
FROM (
SELECT "comments".*,
CASE
WHEN count("comments_post"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_post"."title", "comments_post"."user"::JSON))::text
END AS "post"
FROM (
SELECT "comments".*,
CASE
WHEN count("comments_user"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_user"."name"))::text
END AS "user"
FROM "comments"
LEFT JOIN (
SELECT "comments_user".*
FROM "users" "comments_user"
) "comments_user" ON "comments"."user_id" = "comments_user"."id"
GROUP BY "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content"
) "comments"
LEFT JOIN (
SELECT "comments_post".*
FROM (
SELECT "comments_post".*,
CASE
WHEN count("comments_post_user"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_post_user"."name"))
END AS "user"
FROM "posts" "comments_post"
LEFT JOIN (
SELECT "comments_post_user".*
FROM "users" "comments_post_user"
) "comments_post_user" ON "comments_post"."user_id" = "comments_post_user"."id"
GROUP BY "comments_post"."id"
) "comments_post"
) "comments_post" ON "comments"."post_id" = "comments_post"."id"
GROUP BY "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content",
"comments"."user"
) "comments"
LIMIT 1
더 자세한 내용은 관계형 쿼리 문서에서 확인할 수 있습니다.
모든 컬럼에 기본값을 사용해 행 삽입하기
이제 빈 객체나 빈 객체 배열을 제공하면 Drizzle이 데이터베이스에 모든 기본값을 삽입합니다.
// 모든 기본값을 사용해 1개의 행 삽입
await db.insert(usersTable).values({});
// 모든 기본값을 사용해 2개의 행 삽입
await db.insert(usersTable).values([{}, {}]);