2024年12月19日

Prisma ORM 的五大誤區

瞭解 Prisma ORM 五大常見誤區背後的真相。在本文中,我們將揭穿這些誤區,探究其根源,並趣味性地辨別事實與虛構。

Top 5 Myths about Prisma ORM

誤區1:Prisma ORM 速度慢

我們於 2021 年首次釋出 用於生產環境的 Prisma ORM 時,遵循了“先讓它工作,再讓它正確,最後讓它快速”的方法。這意味著 Prisma ORM 的初始版本並沒有特別針對速度進行最佳化。

然而,自那以後,我們投入了大量精力進行效能最佳化,幾乎在每個版本中都發布了效能改進。

我們還建立了開源的 ORM 基準測試,比較了 TypeScript 生態系統中三種最流行的 ORM,發現 Prisma ORM 的效能與其他 ORM 相似,有時甚至更快。

幾乎每個版本都有重大的效能改進

Prisma ORM 一直遵循穩定可靠的三週釋出週期。如果你檢視 prisma/prisma 倉庫的 釋出頁面,你會注意到幾乎每個版本都帶有一些效能改進——無論是特定 SQL 查詢的最佳化(如 5.11.0, 5.9.0, 5.7.0, 5.4.0, 5.2.0, 5.1.0, … 中所示),引入新的批次查詢,如 createManyAndReturn(在 5.14.0 中),將 冷啟動速度提高了 9 倍(在 5.0.0 中),還是引入了 對原生基於 JS 的驅動的支援(在 5.4.0 中)。

我們還在將基於 Rust 的查詢引擎從 Rust 重寫到 TypeScript,以節省語言邊界之間序列化的開銷,並期望這次更改能帶來顯著的效能改進。

Prisma ORM 允許你選擇最佳的 JOIN 策略

對於使用 Prisma ORM 的開發者來說,另一個巨大的進步是能夠為其關係查詢選擇最佳的 JOIN 策略

原則上,當你需要查詢透過 外部索引鍵 關聯的多個表中的資料時,有兩種不同的方法:

資料庫級別:在單個查詢中使用 JOIN 關鍵字

使用這種方法,你向資料庫傳送一個使用 SQL JOIN 關鍵字的單一查詢,並讓資料由資料庫直接 連線

Blog image

應用級別:傳送多個查詢並在應用程式中進行連線

在應用級別進行連線時,你向資料庫傳送針對單個表的多個查詢,然後自己在應用程式中 連線 資料。

Blog image

何時使用哪種?

根據你的用例、資料集、模式以及其他幾個因素,一種策略可能比另一種更具效能。應用級別的連線方法也稱為 連線分解 ,常用於高效能環境中。

許多高效能網站使用連線分解。你可以透過執行多個單表查詢而不是多表連線來分解連線,然後R在應用程式中執行連線。

高效能 MySQL, 第二版 | O'Reilly

在 Prisma ORM 5.7.0 之前,Prisma ORM 總是使用應用級別的 JOIN 策略。然而,隨著 5.7.0 版本的釋出,我們現在允許你根據你的用例選擇最佳的 JOIN 策略,確保你的查詢始終能獲得最佳效能。

ORM 基準測試:無重大效能差異

經過所有這些改進,我們想知道 Prisma ORM 在效能方面與其他 ORM 庫相比處於什麼位置。因此,我們建立了透明的基準測試,比較了 TypeORM、Drizzle ORM 和 Prisma ORM 的查詢效能。

基準測試倉庫是開源的,我們邀請所有人重現結果並與我們分享。

Blog image

那麼,基準測試顯示了什麼?

總結:根據我們收集的資料,無法得出結論說某個 ORM 總是 比其他 ORM 表現更好。相反,它取決於具體的查詢、資料集、模式以及執行查詢的基礎設施。

你可以在這裡閱讀更多關於基準測試的設定、方法和結果:效能基準測試:比較 TypeScript ORM 和資料庫的查詢延遲

使用 Prisma Optimize 加快你的查詢速度

執行基準測試的一個重要發現是,無論使用何種工具,都可以編寫快速和慢速的查詢。這意味著,最終確保資料庫查詢快速的重擔實際上在於開發者自身。

Blog image

為了確保使用 Prisma ORM 的開發者能儘可能地加快查詢速度,我們最近推出了 Prisma Optimize —— 一個分析你使用 Prisma ORM 傳送給資料庫的查詢,並提供改進建議的工具。

誤區2:無法使用低階資料庫功能

Prisma ORM 作為一種 ORM,天生就提供 SQL 的更高層抽象,以提高與資料庫互動時的生產力、信心和整體開發者體驗。

這種更高層次的抽象體現在 人類可讀的 Prisma schema(用於描述資料庫結構)和 直觀的 Prisma Client API(用於查詢資料庫)中。

然而,鑑於抽象有時也會使訪問底層技術功能(對於 Prisma ORM 而言:資料庫)變得不可能,因此需要一個適當的“逃生艙”來降級到更低的抽象層級。

因此,為了不犧牲在更高階場景或邊緣情況可能需要的重要功能,Prisma ORM 為開發者提供了方便的回退機制,以訪問資料庫的底層功能。

定製化遷移允許開發者使用任何 SQL 功能

雖然不可能在 Prisma schema 中表示資料庫可能擁有的 所有 功能,但你仍然可以透過定製由 Prisma Migrate 生成的遷移檔案來利用這些功能。

為此,你只需在建立新遷移時使用 --create-only 標誌,並在將其應用到資料庫之前進行編輯。

使用定製化遷移,你可以自由地操作資料庫 schema,同時確保所有更改都由 Prisma Migrate 執行並記錄在其遷移歷史中。

在 Prisma ORM 中編寫型別安全的 SQL

在查詢方面,開發者有兩種主要方式可以回退到原始 SQL,並編寫無法使用高階查詢 API 表達的查詢。

TypedSQL:使原始 SQL 型別安全

Prisma ORM 現在為你提供了兩全其美的方案:為大多數查詢提供方便的高階抽象,以及為原始 SQL 提供靈活、型別安全的逃生通道。

考慮這個你可能需要在應用程式中編寫的原始 SQL 查詢示例:

生成步驟完成後,你將能夠透過 Prisma Client 中新的 $queryRawTyped 方法使用 conversionByVariant 查詢。

在我們的部落格上了解更多: TypedSQL 釋出:使用 Prisma ORM 讓你的原始 SQL 查詢型別安全

使用 Kysely SQL 查詢構建擴充套件

另一個替代方案是使用 Kysely 的 Prisma Client 擴充套件,它允許開發者使用其 TypeScript API 構建 SQL 查詢。例如,使用 Kysely 擴充套件,你可以像這樣使用 Prisma 編寫 SQL 查詢:

這使你無需離開 TypeScript 和 Prisma ORM 即可編寫高階 SQL 查詢。

趣事:Kysely 的核心維護者 Igal 最近加入了我們的 Prisma 團隊 😄

誤區3:Prisma ORM 底層使用 GraphQL

根據你在 Prisma 社群活躍的時間長短,這可能會讓你感到驚訝:Prisma 曾經是一個名為 Graphcool 的 GraphQL 後端即服務提供商。

Blog image

2018 年,Graphcool 品牌重塑為 Prisma,並從 API 層級降到資料庫層級,進一步“下放抽象”。

Prisma 的第一個版本(在成為 ORM 之前)是位於你的 API 伺服器和資料庫 之間 的 CRUD GraphQL 層。

在此階段,Prisma 1 提供的主要價值是方便的資料建模、遷移查詢,所有這些都是透過 GraphQL 完成的。

為了簡化 Prisma 的使用並避免要求使用者設定和維護一個完全獨立的伺服器,我們用 Rust 重寫了 Prisma 的 GraphQL 引擎,使其可以透過 npm install 下載為二進位制檔案。

查詢引擎作為應用程式伺服器上的一個 side-car 程序執行一個 GraphQL 伺服器。開發者使用 Prisma Client 與其互動並用 TypeScript 編寫查詢。這是 Prisma ORM 的初始架構。

從那時起,我們對架構進行了無數次最佳化。最顯著的是,我們引入了 N-API 用於 Rust 和 TypeScript 之間的通訊,用自定義的 基於 JSON 的傳輸協議 替換了 GraphQL,支援使用 JS 原生資料庫驅動 等等!

如今,Prisma ORM 中已沒有任何 GraphQL 的痕跡——我們也不會止步於此,我們將繼續改進 Prisma ORM 的架構。我們的下一步是將負責生成 SQL 的查詢引擎從 Rust 遷移到 TypeScript,使 Prisma ORM 更加高效。

誤區4:Prisma Client 必須位於 node_modules

開發者對 Prisma ORM 的一個常見誤解是,生成的 Prisma Client 庫 必須 位於 node_modules 中。

然而,node_modules 只是 預設 位置,旨在提供熟悉的開發者體驗並實現簡單的匯入。

該位置可以透過在 generator 塊上提供自定義 output 路徑來輕鬆定製。

在這種情況下,你需要調整 import 語句,並從檔案系統匯入 Prisma Client。考慮到上面的示例,現在的 import 將會是這樣:

這在單體倉庫(monorepo)或其他特殊環境中非常有用,因為在這種情況下,將 Prisma Client 生成到 node_modules 中可能會導致問題。

誤區5:Prisma 與無伺服器/邊緣計算不相容

當 Prisma ORM 設計時,無伺服器(Serverless)和邊緣(Edge)部署仍是早期的新興技術。自那時起,它們已成為許多開發團隊依賴的流行部署模型。

Prisma ORM 最初的架構,包括查詢引擎二進位制檔案和內部 GraphQL 伺服器,並未針對無伺服器環境進行最佳化,存在許多問題:

  • 基於 GraphQL 的傳輸協議導致冷啟動緩慢。
  • 無法使用現代資料庫提供商(如 Neon 和 PlanetScale)的無伺服器驅動;這完全阻止了在邊緣環境中使用 Prisma Client。
  • 查詢引擎二進位制檔案導致包體積過大。
  • 如果本地機器與目標機器不同,需要宣告 binaryTargets,增加了複雜性。

我們已經認識到所有這些問題,並隨著時間的推移,實施瞭解決方案,大幅改善了 Prisma ORM 在無伺服器環境中的開發者體驗(DX)。

  • 冷啟動已不再是問題,因為我們已從查詢引擎內部移除了 GraphQL,並將冷啟動速度提高了 9 倍
  • 無伺服器(Serverless)和其他JS 原生資料庫驅動(如 pg)現在可以透過驅動介面卡與 Prisma ORM 一起使用。
  • 我們已將 Prisma ORM 的包大小減少到 1MB 以下,使其可以在主要邊緣函式提供商(如 Cloudflare,其免費計劃限制為 3MB)的免費計劃中使用。
  • ……我們還在致力於進一步的改進:從 Rust 遷移到 TypeScript 將消除宣告 binaryTargets 的需要,並總體上使 Prisma ORM 的部署比以往任何時候都更加順暢。

幫助我們讓 Prisma ORM 成為最棒的資料庫庫 💚

在 Prisma,我們高度重視社群提供的反饋!雖然過去關於 Prisma ORM 的一些誤解可能屬實,但我們聽取了使用者的意見,並一直在努力改善這些情況。

如果你對我們的開源治理方法感興趣,請檢視Prisma ORM 宣言

我們將繼續努力,使 Prisma ORM 成為 TypeScript 生態系統中效能最佳、開發者體驗(DX)最好的資料庫庫。請透過 GitHubDiscordX 告訴我們你還希望看到哪些改進 🙌

如果你對 Prisma ORM 感到興奮,可以透過在開發者社群中看到這些誤解時分享這篇文章來幫助我們澄清它們。此外,如果還有其他你想讓我們揭穿的誤區,請告訴我們

不要錯過下一篇文章!

訂閱 Prisma 新聞通訊

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