2025 年 9 月 9 日

为什么 Prisma ORM 检查类型比 Drizzle 更快

类型性能与运行时速度对于开发者体验同样重要。缓慢的类型意味着编辑器卡顿、自动补全失效以及漫长的 CI 运行时间。本文将对 Prisma ORM 和 Drizzle ORM 进行基准测试,以展示它们不同的方法如何影响 TypeScript 编译器的性能。

Graphic with the headline 'Prisma checks query types faster than Drizzle.' A comparison table shows Prisma with 428 type instantiations versus Drizzle with 41,150, a difference of +9514%. Check time is listed as 101ms for Prisma and 219ms for Drizzle, a difference of +117%. The design includes an upward arrow line graph in the background, emphasizing performance gains.

什么是类型性能以及为什么它很重要

当我们考虑应用程序的性能时,我们通常会想到运行时指标:响应时间、冷启动、数据库查询速度。但 TypeScript 开发者知道,性能还有另一个维度:类型检查性能

这是 TypeScript 编译器在开发过程中分析、评估和验证类型的效率。当类型性能下降时,开发者会立即通过编辑器卡顿或 CI 流程缓慢感受到。

  • 自动补全需要几秒钟才能加载,或者完全失效
  • 跳转到定义功能停止工作
  • tsc 在 CI 中需要数分钟才能完成

TypeScript 本质上是在编译时进行运行时计算,尤其是在严重依赖高级类型功能的现代库中。当你的类型变得庞大或深度递归时,TypeScript 的工作就会变得指数级困难。结果呢?迟钝、令人沮丧的开发者体验。

Prisma ORM vs. Drizzle:不同的类型系统哲学

在本文中,我们将比较 Prisma ORM 和 Drizzle ORM 的类型性能。尽管两者都旨在提供类型安全的数据库访问,但它们遵循着根本不同的哲学。

  • Prisma ORM 使用代码生成: 它通过 prisma generate 命令在构建时预计算类型,并将它们写入 .d.ts 文件。你的编辑器只需加载这些预计算的类型。这种方法建立在 Prisma Schema Language 之上,这是一种定义数据模型的声明性方式,使得类型生成成为可能。
  • Drizzle ORM 使用类型推断:它在纯 TypeScript 中定义你的 schema,并让编译器实时从其中推断类型。这在你每次编写查询时都会发生。

以下是两种方法的主要区别和权衡:

代码生成 (Prisma ORM)类型推断 (Drizzle)类型创建时间prisma generate 期间 — 写入 .d.ts 文件即时 — 在你编写代码时由 TypeScript 编译器推断编辑器/CI 如何看待它们加载预生成的 .d.ts 类型直接从你的 schema 和查询重新计算类型对类型检查性能的影响稳定,因为大部分计算提前完成更具变数,因为每个查询都会触发新的推断

方法论:使用 @ark/attest 对类型性能进行基准测试

为了创建我们的类型检查基准测试,我们与 TypeScript 专家 David Blass 合作,他是类型安全运行时验证库 ArkType 的创建者。

David 在 TypeScript 生态系统中因其在推进类型系统工具和性能方面的全职开源工作而闻名,他构建了 @ark/attest,这是我们用于测试和基准测试类型级别逻辑的库。

基准测试设置可在 GitHub 上的开源仓库中找到,它包含三个主要要素:

基准测试框架

@ark/attest 提供了一种编写测试的方法,可以测量类型实例化(编译器需要评估的类型数量)和检查时间(类型检查文件所需的时间)。这比单独计时 tsc 运行更可靠,因为实例化在不同环境和 TypeScript 版本之间是确定性的。

Schema

我们使用了经典的 Northwind schema 作为真实的数据库模型。Prisma 和 Drizzle 的基准测试都只保留了类型相关的表达式,以避免运行时逻辑干扰。

基准测试文件

每个 ORM 都通过两种方式进行测试:

对于 Drizzle,我们包含了两个变体,因为它们代表了不同的抽象级别:

  • 关系查询构建器 API (RQB): 一个具有关系帮助器的高级 API(drizzle.relational.bench.ts)。这是与 Prisma Client 最接近的概念等效项,也是我们分析中的主要比较点。
  • SQL 查询构建器: 一个更低级的构建器(drizzle.query.ts),更直接地映射到 SQL。它提供了更大的灵活性,但会生成更复杂的类型签名,这通常会给编译器带来更大的压力。

仓库的结构使得每个基准测试文件都包含一个或多个 attest.bench 块。例如,以下是 Prisma 查询基准测试的简化片段:

这些是 Drizzle 基准测试中的等效片段:

当基准测试执行时,@ark/attest 库会类型检查每个块并记录:

  • 类型实例化:触发的类型实例化数量
  • 检查时间:经过的编译器时间(在 AWS EC2 m7i.large 实例上测量)

这种方法确保了适当的比较:相同的 schema、相同的查询、相同的 TypeScript 版本,通过相同的框架测量,从而得出相同的结果指标。

结果:测量类型实例化和检查时间

我们报告了两组在 m7i.large 实例上测量的结果。第一组将 Prisma ORM 与 Drizzle 0.44.4(测试时的稳定版本)进行比较,并作为主要数据集。第二组测量的是 Drizzle 最近发布的具有改进类型检查性能的测试版

Prisma ORM vs Drizzle 0.44.4 (主要结果)

Schemas

类型实例化

Prisma ORMDrizzle ORM差异(数量)差异(%)42841150+40722+9514%

检查时间

Prisma ORMDrizzle ORM差异(毫秒)差异(%)205.02ms601.58ms+396.56ms+193%

查询

类型实例化

标签Prisma ORMDrizzle RQB API差异(%)客户:获取信息437731+67%客户:搜索213341+60%员工:获取信息10501710+63%供应商:获取信息429697+62%产品:获取信息9001626+81%产品:搜索213341+60%订单:获取所有15381441-6%订单:按ID获取15421649+7%订单:获取信息7471950+161%平均7851165+48%

检查时间

Prisma ORMDrizzle RQB API差异(%)335ms697ms+108%

Prisma ORM vs Drizzle 1.0.0-beta.1-2acab7f

Drizzle 最近发布了一个带有类型检查改进的测试版。我们针对此版本重新运行了测试套件,以提供最新的比较;下面的检查时间是同一台机器上的重新测量结果。

Schemas

类型实例化

Prisma ORMDrizzle ORM差异(数量)差异(%)4285017+4589+1072%

检查时间

Prisma ORMDrizzle ORM差异(毫秒)差异(%)191.18ms369.19ms+178.01ms+93%

查询

类型实例化

标签Prisma ORMDrizzle RQB API差异(%)客户:获取信息437364-17%客户:搜索213282+32%员工:获取信息1050514-51%供应商:获取信息429364-15%产品:获取信息900514-43%产品:搜索213298+40%订单:获取所有1538955-38%订单:按ID获取15421022-34%订单:获取信息747459-39%平均785530-32%

检查时间

Prisma ORMDrizzle RQB API差异(%)284ms416ms+47%

Drizzle 关系查询构建器与 Prisma ORM 的结果分析

为了公平比较,本分析着眼于 Prisma ORM 与 Drizzle 的关系查询构建器 (RQB) API,因为两者都提供了高级关系抽象。我们还分析了与 Drizzle 测试版比较的结果,因为该版本比 Drizzle ORM 当前的实时版本表现明显更好。

Schema 基准测试显示出最大的差异。Prisma 生成的 schema 类型只需要数百次实例化,而 Drizzle 推断的 schema 需要超过五千次。这是因为 Drizzle 要求编译器在每次构建时“从第一性原理重新推导一切”,而 Prisma 则在其代码生成步骤中“预先加载”了这项工作。

结果是,Prisma 的检查时间不仅更快,而且随着 schema 的增长也更可预测。实际上,这意味着随着应用程序的扩展,Prisma 的类型检查性能保持相对稳定且易于预测,而 Drizzle 的性能可能随着 schema 的增长而以尖峰或指数方式下降。

对于查询,Drizzle 测试版导致更少的类型实例化,但检查时间仍然更高,这表明类型实例化并非最重要的指标,在评估实际类型检查性能时,实际测量编译器所需的时间仍然至关重要。

为什么 Prisma ORM 在类型检查方面表现更好

那么,造成这种差异的原因是什么?Prisma 的几项架构优势导致了更好的类型性能,让我们逐一介绍。

代码生成作为预计算

Prisma 在 prisma generate 期间一次性执行繁重的类型工作。输出的 .d.ts 文件缓存了类型关系,因此编译器无需在每次按键时重复进行。

Prisma 有一个很大的优势——在构建时有一个步骤,会构造大量的类型。

David BlassDavid Blass

相比之下,Drizzle 在每次编写查询时都会重新推导类型。这解释了为什么 Prisma 的实例化次数通常要少得多。

更扁平、缓存友好的类型

Prisma 生成的类型避免了深度递归,优先使用接口进行结构复用,并最小化条件联合——所有这些都与 TypeScript 的内部缓存模型保持一致。

避免类型系统陷阱

通过生成类型而不是推断类型,Prisma 避免了常见的陷阱,例如 非同态映射类型深度嵌套条件类型大量交集联合,这些模式已知会减慢 TypeScript 编译器的速度。

我们如何在 Prisma ORM 中优化类型检查

作为与 David Blass 合作的一部分,我们也为我们的类型检查性能进行了一次重大的优化工作。以下是我们所做的一些事情的总结:

  • 结构去重:重构了生成的输出(例如 commonInputTypes),以复用接口而不是重复形状。结果:文件大小减少 76% (339 → 82 LOC),检查时间减少 45%。
  • 同态映射类型:重写了映射类型以保留可选修饰符、JSDoc 和跳转到定义。这既提高了开发者体验,也提高了编译器效率。
  • readonly 数组作为基本情况:防止了只读元组破坏对 any[] 的可赋值性的推断陷阱。
  • 简化的抽象:删除了不必要的实用程序,这些实用程序要么复制了内置功能,要么在没有好处的情况下引入了额外的间接性。
  • 改进的输入验证模式:将多步骤的泛型链整合为单个映射类型验证器,以提高可读性和性能。
  • 类型性能 CI 测试:添加了 CI 护栏,用于快照实例化/检查时间以防止回归(PR #26894)。

如果您对细节感到好奇,可以查看我们实施优化的 PR(#27775#27777)。

结论:类型安全不必以牺牲开发者体验为代价

Prisma ORM 和 Drizzle ORM 都拥抱 TypeScript,但它们走的是截然不同的道路。Prisma ORM 使用代码生成来保持类型快速稳定。Drizzle ORM 依赖类型推断来实现灵活性,但这种灵活性可能会带来性能成本。

我们的基准测试显示如下:

  • Schemas (Drizzle 0.44.4 vs Prisma ORM): Prisma ORM 只需要数百次类型实例化,而 Drizzle ORM 需要超过 40,000 次(约 95 倍的差异)。结果是,Prisma ORM 的检查时间快了约 2.9 倍。
  • Queries (Drizzle 0.44.4 RBQ API vs Prisma ORM): Prisma ORM 平均减少了 48% 的类型实例化,检查时间快了约 2.1 倍。

请注意,Drizzle 的 1.0.0 测试版显著减少了 schema 实例化次数至约 5k(与 Prisma ORM 相比增加 1072%)。对于查询,Drizzle 的 RQB 现在平均比 Prisma 少 32% 的实例化,但检查时间仍然慢约 1.5 倍。

您可以在我们的开源仓库中探索所有基准测试文件。

如果您正在构建一个大型、复杂的应用程序,其中开发者效率和 CI 性能很重要,那么 Prisma ORM 的方法扩展性更强,速度更快。最重要的是,类型性能就是开发者体验。您的编辑器响应越快,您的反馈循环就越快,您的开发者就越满意。

我们使用了 Drizzle ORM 版本 0.44.4 (稳定版) 和 1.0.0-beta.1-2acab7f,并将其与 Prisma ORM 6.15.0 进行了比较。

不要错过下一篇文章!

订阅 Prisma 新闻通讯

© . This site is unofficial and not affiliated with Prisma Data, Inc.