如果你受够了传统 ORM 的黑箱魔法和性能损耗Drizzle ORM 可能是你一直在找的答案。它是什么Drizzle ORM 是一个 TypeScript 优先的数据库工具链2023 年开源后迅速获得 25k GitHub Star。和 Prisma、TypeORM 这些老牌选手不同Drizzle 的设计哲学只有一句话你写的 TypeScript 代码1:1 映射到 SQL。没有隐藏的查询生成没有不可预测的 N1没有臃肿的代理层。定义 Schema → 写查询 → 拿到结果整个过程透明可控。目前支持的数据库PostgreSQL、MySQL、SQLite、PlanetScale、Neon、Turso、Cloudflare D1、AWS Data API 等几乎覆盖了现代服务端所有主流选型。核心优势1. 零黑箱——你能看到每一行 SQL大多数 ORM 的查询构建器会在运行时动态拼接 SQL你根本不知道最后发出的查询是什么。Drizzle 的做法完全不同const result await db .select({ name: users.name, orderCount: count(orders.id), }) .from(users) .leftJoin(orders, eq(users.id, orders.userId)) .groupBy(users.name); // 在开发模式下可以直接拿到生成的 SQL // SELECT users.name, count(orders.id) FROM users // LEFT JOIN orders ON users.id orders.userId // GROUP BY users.name不需要 console.log(query.toSQL())不需要猜测。Drizzle 的查询 API 直接对标 SQL 语义你写什么就得到什么。这对调试和性能排查来说价值巨大。2. 运行时开销几乎为零Drizzle 不维护对象图、不做脏检查、不搞懒加载。它只是一个类型安全的查询构建器加一个轻量的数据库驱动封装。实际压测数据来源Drizzle 官方 benchmark工具简单查询 (ops/s)联表查询 (ops/s)Drizzle52,00018,500Prisma18,2006,800TypeORM9,4003,200差距在三到五倍之间。原因很简单Prisma 的查询引擎是 Rust 写的二进制文件通过 HTTP/gRPC 与 Node.js 通信中间多了一次序列化TypeORM 有 Active Record 和 Data Mapper 双重模式的包袱。Drizzle 直接用 pg / mysql2 / better-sqlite3 这些底层驱动没有中间层。3. 类型安全贯穿全链路从 Schema 定义到查询结果TypeScript 类型始终保持完整import { pgTable, text, integer, timestamp } from drizzle-orm/pg-core; export const users pgTable(users, { id: integer(id).primaryKey().generatedAlwaysAsIdentity(), name: text(name).notNull(), email: text(email).notNull().unique(), createdAt: timestamp(created_at).defaultNow(), }); type User typeof users.$inferSelect; // 自动推导出 SELECT 结果的类型 type NewUser typeof users.$inferInsert; // 自动推导出 INSERT 输入的类型迁移文件也是 .sql 明文你在 drizzle/ 目录下能看到每一次迁移的完整 SQL。这意味着你可以在生产环境直接拿迁移文件审计而不需要依赖某个 GUI 工具或黑箱命令。4. 极致的 Bundle 体积Drizzle 的模块化设计允许按需引入最终打包体积做到极致drizzle-orm 核心仅 ~11KB gzipped加上 drizzle-orm/pg-core 和 drizzle-orm/node-postgres总计约 30KB对比 Prisma Client 动辄 2MB 的体积这在 Serverless / Edge Function 场景下是决定性的差异——冷启动时间直接受包体积影响。5. 原生 SQL 的优雅降级不是所有查询都适合用查询构建器。当你需要写复杂 CTE、窗口函数、递归查询时Drizzle 允许你直接写原生 SQL 并且拿到完整的类型推断import { sql } from drizzle-orm; const result await db.all{ total: number; month: string }(sql SELECT DATE_TRUNC(month, created_at) AS month, SUM(amount) AS total FROM orders WHERE created_at ${startDate} GROUP BY 1 ORDER BY 1 );你不是在逃离 ORM而是在需要的时候直接把它当成一个类型安全的数据库客户端。适用场景场景一Serverless / Edge 环境在 Cloudflare Workers、Vercel Edge Functions、AWS Lambda 这类短生命周期环境中包体积和冷启动时间是核心指标。Drizzle 的 ~30KB 体积配合原生驱动直连比 Prisma 的冷启动快 3-5 倍。而且 Drizzle 对 Cloudflare D1、Neon Serverless、PlanetScale HTTP API 都有第一方支持不需要自己折腾连接池。场景二需要 SQL 审计和精细控制的团队金融、医疗、合规要求严格的行业数据库迁移必须逐条审计。Drizzle 的 SQL 文件迁移和 Drizzle Kit 生成的纯 SQL 文件可以直接走审批流程。相比之下Prisma 的迁移目录里虽然也有 SQL但它的 schema.prisma 才是真实数据源你没法绕过那层抽象。场景三微服务与多语言项目如果你的后端是 Go TypeScript 混排或者逐步从 Rails 迁移到 Node.jsDrizzle 的「用 DDL 定义真实数据源 用 Zod Schema 生成 Drizzle Schema 代码」这条管线能让你从已有的数据库逆推出 TypeScript 代码npx drizzle-kit pull执行后自动读取你的数据库结构生成对应的 Schema 文件。对于已经运行了几年的老数据库这种零成本的接入方式是 TypeORM 的 CLI 做不到的。场景四高性能 API 服务当你需要榨干 PostgreSQL/MySQL 的每一分性能同时又不想放弃 TypeScript 的类型安全时Drizzle 是最接近裸写的选择。它支持批量 INSERT、upsert、CTE、窗口函数、事务嵌套、部分索引、物化视图等高级特性且全部有类型提示。实操从零搭建一个博客系统下面以一个简单的博客 API 为例展示 Drizzle 的完整工作流。Step 1初始化项目mkdir drizzle-blog cd drizzle-blog npm init -y npm install drizzle-orm postgres npm install -D drizzle-kit types/node typescript tsxStep 2定义 Schema创建 src/schema.tsimport { pgTable, serial, text, integer, timestamp, boolean } from drizzle-orm/pg-core; export const users pgTable(users, { id: serial(id).primaryKey(), name: text(name).notNull(), email: text(email).notNull().unique(), createdAt: timestamp(created_at).defaultNow(), }); export const posts pgTable(posts, { id: serial(id).primaryKey(), title: text(title).notNull(), content: text(content).notNull(), published: boolean(published).default(false), authorId: integer(author_id) .notNull() .references(() users.id), createdAt: timestamp(created_at).defaultNow(), updatedAt: timestamp(updated_at).defaultNow(), });Step 3配置 Drizzle Kit创建 drizzle.config.tsimport { defineConfig } from drizzle-kit; export default defineConfig({ schema: ./src/schema.ts, out: ./drizzle, dialect: postgresql, dbCredentials: { url: process.env.DATABASE_URL!, }, });Step 4生成并执行迁移npx drizzle-kit generate # 生成 SQL 迁移文件 npx drizzle-kit migrate # 执行迁移这一步会在 drizzle/ 目录生成类似 0000_bright_iron_man.sql 的文件内容就是你 Schema 定义对应的 CREATE TABLE / ALTER TABLE 语句。Step 5建立数据库连接创建 src/db.tsimport { drizzle } from drizzle-orm/node-postgres; import { Pool } from pg; import * as schema from ./schema; const pool new Pool({ connectionString: process.env.DATABASE_URL, }); export const db drizzle(pool, { schema });Step 6编写业务逻辑import { db } from ./db; import { users, posts } from ./schema; import { eq, and, desc, count } from drizzle-orm; // CRUD // 创建用户 async function createUser(name: string, email: string) { const [user] await db .insert(users) .values({ name, email }) .returning(); return user; } // 按 ID 查询用户 async function getUserById(id: number) { return db.query.users.findFirst({ where: eq(users.id, id), with: { posts: true, // 自动联表查询该用户的所有文章 }, }); } // 分页查询已发布文章 async function getPublishedPosts(page: number, pageSize: number) { return db.query.posts.findMany({ where: eq(posts.published, true), orderBy: desc(posts.createdAt), limit: pageSize, offset: (page - 1) * pageSize, with: { author: { columns: { name: true }, // 只取作者名 }, }, }); } // 批量发布文章 async function publishPosts(ids: number[]) { return db .update(posts) .set({ published: true, updatedAt: new Date() }) .where(and(eq(posts.published, false), /* ... in 条件用 inArray */)); } // 统计每个作者的已发布文章数 async function getAuthorStats() { return db .select({ authorName: users.name, postCount: count(posts.id), }) .from(users) .leftJoin(posts, eq(users.id, posts.authorId)) .groupBy(users.id, users.name) .having(({ postCount }) sql${postCount} 0); }Step 7事务支持import { db } from ./db; async function transferPostOwnership( postId: number, fromUserId: number, toUserId: number ) { await db.transaction(async (tx) { // 检查当前归属 const post await tx.query.posts.findFirst({ where: and( eq(posts.id, postId), eq(posts.authorId, fromUserId) ), }); if (!post) { throw new Error(文章不存在或不属于该用户); } // 转移归属 await tx .update(posts) .set({ authorId: toUserId, updatedAt: new Date() }) .where(eq(posts.id, postId)); }); }与其他 ORM 的对比小结维度DrizzlePrismaTypeORM学习曲线需要 SQL 基础有自己的 DSL需要理解 Active Record / Data Mapper性能接近原生驱动中等Rust 引擎桥接有开销较低包体积~30KB~2MB~500KBSQL 可见性1:1 映射完全可见黑箱需要 Prisma Studio 才能查看部分可见迁移可审计性纯 SQL 文件依赖 schema.prisma依赖装饰器或配置文件Edge 支持官方支持 D1、Neon 等有 Edge Client 但有限制不友好社区成熟度增长快生态较新最成熟老牌但维护放缓原生 SQL 支持一等公民带类型推断需要 $queryRaw需要 query()迁移可逆性支持 drizzle-kit drop支持 migrate dev --create-only 但需手动回滚需手动管理什么时候不该用 Drizzle坦诚地说Drizzle 不适合以下情况团队完全没有 SQL 基础。Drizzle 假设你理解 SQL 语义select / where / join / groupBy 这些 API 直接映射 SQL 概念。如果团队更习惯 Prisma 那种声明式的 include 语法Drizzle 会有上手成本。需要 Prisma Studio 这样的 GUI 数据库浏览工具。Drizzle 有 drizzle-kit studio但目前还比较简陋功能远不如 Prisma Studio 完善。项目深度依赖 Prisma 生态比如 nestjs-prisma、prisma-nestjs-graphql 这类社区工具链。迁移成本需要评估。极度保守的企业环境要求 ORM 有至少 5 年以上生产实践和商业支持。Drizzle 第一个正式版本是 2023 年底发布的在大厂核心系统的选型中可能还排不上优先级。总结Drizzle ORM 不是要取代 SQL而是让 SQL 在 TypeScript 里拥有完整的类型安全。对于需要精细化控制查询、追求性能、工作在 Serverless 环境的团队来说它是一个非常务实的选择。SQL 不会消失只会换一种方式被写出来。Drizzle 把这件事做得足够干净。