Drizzle
本页比较 Prisma ORM 和 Drizzle。
Drizzle 与 Prisma ORM
虽然 Prisma ORM 和 Drizzle 解决的是类似的问题,但它们的工作方式却截然不同,并且各有优劣。选择哪一个将取决于您的项目需求以及对项目重要的具体权衡。
Drizzle 是一种传统的 SQL 查询构建器,它允许您使用 JavaScript/TypeScript 函数组合 SQL 查询。它可以用于查询数据库或运行迁移。Drizzle 还提供了一个查询 API,该 API 提供了比 SQL 更高级别的抽象,可用于读取嵌套关系。Drizzle 架构是在 TypeScript 文件中定义的,这些文件用于生成 SQL 迁移,然后在数据库上执行。
Prisma ORM 缓解了传统 ORM 的许多问题,例如臃肿的模型实例、将业务逻辑与存储逻辑混合、缺乏类型安全或由延迟加载等原因导致的不可预测的查询。它使用 Prisma Schema 以声明的方式定义应用程序模型。然后,Prisma Migrate 允许从 Prisma Schema 生成 SQL 迁移,并在数据库上执行。CRUD 查询由 Prisma Client 提供,Prisma Client 是一个轻量级且完全类型安全的数据库客户端,适用于 Node.js 和 TypeScript。
类型安全
Drizzle 并不完全类型安全。正如第三方 比较研究 中的引述,“Drizzle 给人一种类型安全的印象。但是,只有查询结果有类型信息。您可以使用 Drizzle 编写无效的查询。”
使用 Prisma,您可以获得由生成的类型带来的完全类型安全。这意味着,在编写代码和与团队成员协作时,潜在的错误更少。
API 设计和抽象级别
Drizzle 和 Prisma ORM 在不同的抽象级别上运行。Drizzle 的理念是“如果你了解 SQL,你就了解 Drizzle ORM”。它在 API 中镜像 SQL,而 Prisma Client 提供了一个更高级别的抽象,该抽象是针对应用程序开发人员的常见任务而设计的。Prisma ORM 的 API 设计严重依赖于 让正确的事情变得容易 的理念。
虽然 Prisma Client 在更高级别的抽象上运行,但您可以在任何时候下降到 原始 SQL。但是,完全使用 Prisma ORM 和开发您的应用程序并不需要 SQL 知识。Prisma ORM 的目标是构建一个专注于开发人员体验和生产力的查询语法,这种语法对于开发人员来说很熟悉。您可以在此处了解更多信息:为什么选择 Prisma。
对于无法在 Prisma Client API 中表达的少数查询,Prisma ORM 还提供 TypedSQL,它通过直接使用 .sql
文件提供更熟悉且类型安全的体验。您的现有 SQL 工具和工作流可以与 Prisma Client 协同工作,以处理所需的任何抽象级别。
虽然 Prisma ORM 中可以使用 TypedSQL 提供完全类型的 SQL 查询,但以下部分将探讨 Prisma 和 Drizzle API 如何不同的几个示例以及 Prisma ORM API 设计的原理。
数据建模
Prisma 模型在 Prisma Schema 中定义,而 Drizzle 使用 TypeScript 函数进行表定义。然后导出这些函数并在查询中使用。
Prisma 生成一个轻量级的数据库客户端,该客户端公开一个定制的、完全类型安全的 API 来读取和写入在 Prisma Schema 中定义的模型的数据,遵循 DataMapper ORM 模式。
Prisma ORM 的数据建模 DSL 简洁、简单且易于使用。在 VS Code 中建模数据时,您还可以利用 Prisma ORM 功能强大的 VS Code 扩展,它提供自动完成、快速修复、跳转到定义等功能,从而提高开发人员的生产力。另一方面,Drizzle 的 TypeScript 使用意味着您可以依靠 TypeScript 的强大功能来获得额外的灵活性(例如通过重用代码)。
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int?
author User? @relation(fields: [authorId], references: [id])
}
import {
boolean,
integer,
pgTable,
serial,
text,
uniqueIndex,
varchar,
} from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
email: varchar('email', { length: 256 }).unique(),
})
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: varchar('title', { length: 256 }).notNull(),
content: text('content'),
published: boolean('published'),
authorId: integer('author_id').references(() => users.id),
})
迁移
Drizzle 和 Prisma ORM 的迁移工作方式相似。这两种工具都遵循基于提供的模型定义生成 SQL 文件的方法,并提供一个 CLI 在数据库上执行这些文件。可以在执行迁移之前修改 SQL 文件,以便使用任一迁移系统执行任何自定义数据库操作。
查询
Drizzle 和 Prisma ORM 中都很容易构建简单的查询。使用 Drizzle 的查询 API,这两种方法非常相似。
// find all users
const allUsers = await prisma.user.findMany()
// find a single user
const user = await prisma.user.findFirst({
where: { id: 27 },
})
// find a unique user
const user = await prisma.user.findUnique({
where: { email: '[email protected]' },
})
import { eq } from 'drizzle-orm'
// find all users
const allUsers = await db.query.users.findMany()
// find a single user
const user = await db.query.users.findFirst({
where: eq(users.id, 1),
})
// find a unique post
const user = await db.query.users.findFirst({
where: eq(users.email, '[email protected]'),
})
在执行 create
、update
或 delete
等变异操作时,Drizzle 查询 API 不可用。在这种情况下,您需要使用 Drizzle 的 SQL 类 API。
// create a user
const user = await prisma.user.create({
data: {
name: 'Nilu',
email: '[email protected]',
},
})
// update a user
const user = await prisma.user.update({
where: { email: '[email protected]' },
data: { name: 'Another Nilu' },
})
// delete a user
const deletedUser = await prisma.user.delete({
where: { email: '[email protected]' },
})
// create a user
const user = await db.insert(users).values({
name: 'Nilu',
email: '[email protected]',
})
// update a user
const user = await db
.update(users)
.set({ name: 'Another Nilu' })
.where(eq(users.email, '[email protected]'))
.returning()
// delete a user
const deletedUser = await db
.delete(users)
.where(eq(users.email, '[email protected]'))
.returning()
关系
在 SQL 中处理通过外键连接的记录可能变得非常复杂。Prisma ORM 的 虚拟关系字段 概念为应用程序开发人员提供了一种直观且方便的方式来处理相关数据。Prisma ORM 方法的一些优势是
- 通过流畅的 API 遍历关系(文档)
- 允许更新/创建连接记录的嵌套写入(文档)
- 在相关记录上应用过滤器(文档)
- 轻松且类型安全地查询嵌套数据,无需担心底层 SQL(文档)
- 基于模型及其关系创建嵌套 TypeScript 类型(文档)
- 通过关系字段以直观的方式在数据模型中建模关系(文档)
- 隐式处理关系表(有时也称为 JOIN、链接、枢纽或联接表)(文档)
const posts = await prisma.post.findMany({
include: {
author: true,
},
})
const posts = await db.query.posts.findMany({
with: {
author: true,
},
})
过滤
Drizzle 公开了给定 SQL 方言的底层过滤器和条件运算符。另一方面,Prisma ORM 提供了一组更 通用的运算符,这些运算符易于使用。
Drizzle 和 Prisma ORM 的过滤 API 不同的一个很好的例子是查看 string
过滤器。Drizzle 提供了 like
和 ilike
的过滤器,而 Prisma ORM 提供了开发人员可以使用的更具体的运算符,例如:contains
、startsWith
和 endsWith
。
// case sensitive filter
const posts = await prisma.post.findMany({
where: {
title: 'Hello World',
},
})
// case insensitive filter
const posts = await prisma.post.findMany({
where: {
title: 'Hello World',
mode: 'insensitive',
},
})
// case sensitive filter
const posts = await db
.select()
.from(posts)
.where(like(posts.title, 'Hello World'))
// case insensitive filter
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, 'Hello World'))
const posts = await prisma.post.findMany({
where: {
title: {
contains: 'Hello World',
},
},
})
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, '%Hello World%'))
const posts = await prisma.post.findMany({
where: {
title: {
startsWith: 'Hello World',
},
},
})
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, 'Hello World%'))
const posts = await prisma.post.findMany({
where: {
title: {
endsWith: 'Hello World',
},
},
})
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, '%Hello World'))
分页
Drizzle 只提供 limit-offset 分页,而 Prisma ORM 方便地提供了专用的 API,用于 limit-offset 和基于游标的分页。您可以在文档的 分页 部分了解更多关于这两种方法的信息。
// limit-offset pagination
const postPage = await prisma.post.findMany({
where: {
title: 'Hello World',
},
skip: 6,
take: 3,
})
// cursor-based pagination
const postPage = await prisma.post.findMany({
where: {
title: 'Hello World',
},
cursor: { id: 7 },
take: 3,
})
// limit-offset pagination (cursor-based not currently possible)
const postPage = await db
.select()
.from(users)
.where(ilike(posts.title, 'Hello World%'))
.limit(3)
.offset(6)
可观测性
Drizzle 和 Prisma ORM 都能够记录查询和生成的底层 SQL。
Prisma ORM 在客户端中内置了其他功能,可帮助团队更好地了解他们的数据使用情况。可以在任何时候启用 指标 和 跟踪,它们提供每个查询的信息。这些信息可以与外部工具集成,以便您可以跟踪性能随时间的变化。
其他产品
Drizzle 和 Prisma 都在 ORM 之外提供产品。Prisma Studio 发布后,允许用户通过 GUI 与数据库交互,并允许有限的自托管,供团队内部使用。Drizzle Studio 的发布旨在实现相同的任务。
除了 Prisma Studio 之外,Prisma 还通过 Prisma Data Platform 提供商业产品。
- Prisma Accelerate:一个连接池和全局缓存,与 Prisma ORM 集成。用户可以立即利用连接池,并可以控制单个查询级别的缓存。
- Prisma Pulse:一项变更数据捕获 (CDC) 服务,Prisma Client 可以订阅数据库更改,并以几乎无需设置的方式实时接收更改。
- Prisma Optimize:一个查询分析工具,提供深入的见解、可操作的建议,并允许您与 Prisma AI 交互,以获得更多见解并优化您的数据库查询。
这些产品与 Prisma ORM 相辅相成,提供全面的数据工具,通过遵循 Data DX 原则,使构建数据驱动的应用程序变得容易。
生态系统
Drizzle 和 Prisma ORM 都存在用户希望执行库未直接支持的操作的情况。Drizzle 依靠 SQL 的表达能力来避免这些情况,而 Prisma ORM 则提供 Prisma Client 扩展,允许任何用户为其 Prisma Client 实例添加其他行为。这些扩展也是可共享的,这意味着团队可以开发它们供其所有项目使用,甚至供其他团队使用。
虽然 Drizzle 是一个相对较新的产品,但 Prisma ORM 已于 2021 年发布,并在 JavaScript/TypeScript 空间中已建立良好声誉。它已证明其价值,许多公司信任 生产环境中的 Prisma ORM。
Prisma ORM 还被用作许多元框架和开发平台中首选的数据层工具,例如 Amplication、Wasp、RedwoodJS、KeystoneJS、Remix 以及 t3 stack。
由于其成熟度,Prisma 的社区开发了 大量有用的工具,帮助完成各种 Prisma 工作流程。以下是一些亮点:
zenstack
:一个扩展 Prisma 的工具包,在 Prisma 模式中提供访问控制策略、自动生成的 CRUD API 和前端查询钩子。prisma-erd-generator
:将 Prisma 模式可视化为实体-关系-图 (ERD)。prisma-zod-generator
:从 Prisma 模式生成 Zod 模式。bridg
:允许您使用 Prisma Client 从前端访问数据库。jest-prisma
:用于 Prisma 集成测试的环境,与 Jest 集成。prisma-pothos-types
:在使用 GraphQL Pothos 时,根据 Prisma 模型创建 GraphQL 类型。prisma-trpc-generator
:从 Prisma 模式创建 tRPC 路由器。@cerbos/orm-prisma
:根据来自 Cerbos 的授权策略过滤数据。
数据库支持
Drizzle 和 Prisma ORM 都支持多种不同的数据库。Drizzle 通过 Drizzle 创建的驱动程序实现来实现这种支持,这些实现与现有的第三方数据库驱动程序集成。
Prisma ORM 已经开始添加对 第三方数据库驱动程序 的支持,但主要使用 内置驱动程序 与底层数据库通信。Prisma 还将连接默认设置为 TLS,这提高了安全性。
此外,Prisma ORM 支持 CockroachDB、Microsoft SQL Server 和 MongoDB,而 Drizzle 目前不支持。Prisma ORM 还提供 关系模式,允许 Prisma ORM 为不支持外键约束的数据库引擎模拟外键约束。Drizzle 目前支持 Cloudflare D1、bun:sqlite
以及通过 HTTP 代理的 SQLite,而 Prisma ORM 目前不支持。
基准测试
我们明白,性能是选择 ORM 时的一个关键考量因素。要比较各种 ORM 的性能,您可以使用 Vercel 托管的开源 数据库延迟基准测试工具。这个工具允许您在不同的工作负载和配置下评估各种 ORM 的延迟和吞吐量。通过针对您正在考虑的数据库或数据库提供商运行基准测试,您可以清楚地了解其相对的性能特征,从而做出明智的决策。
或者,您也可以查看我们构建的 基准测试工具 上的发现,该工具比较了流行的 TypeScript ORM,包括 Drizzle。此基准测试是开源的,旨在公平地比较 Node.js 和 TypeScript 生态系统中数据库提供商和 ORM 库之间的数据库查询延迟。
结论
Drizzle ORM 和 Prisma ORM 都是用于数据访问和迁移的工具。Drizzle 侧重于作为 SQL 类语法的薄包装器,而 Prisma 则侧重于提供便捷且富有表现力的 API。其他重要差异包括 Prisma ORM 对 MSSQL 和 MongoDB 的支持,通过 Prisma Client 扩展 支持更多功能,额外的云就绪产品以及强大的生态系统。
另一方面,对于由具有不同数据库经验水平的开发人员(前端、后端和全栈)组成的团队,Prisma ORM 提供了一种全面且易于学习的方法,用于数据访问和管理数据库模式。