讀者 Quintos 問了好問題:文章裡 .NET 6 在用的 SQLite 是微軟版還是 SQLite 官方版?(聽說 SQLite 官方版效能比較好)

我一向是 dotnet add package Microsoft.EntityFrameworkCore.Sqlite 就開心寫 Code,不知道 .NET SQLite 有微軟版跟 SQLite 官方版之別,但被這麼一問我也好奇心起,決定爬文找答案。

我知道 .NET SQLite 需依賴原生程式庫(Native DLL,用 C/C++ 開發),ASP.NET MVC 時代曾遇過缺少 SQLite.Interop.dll 無法運作,印象很深。.NET Framework 時代的 System.Data.SQLite.dll 需要原生程式庫 SQLite.Interop.dll 才能正常執行,而 System.Data.SQLite 專案由 SQLite Development Team 負責維護,並承諾長期支援。(Development and maintenance work is now mostly performed by the SQLite Development Team. The SQLite team is committed to supporting System.Data.SQLite long-term. 參考) 因此,System.Data.SQLite 就是 SQLite 官方版。

.NET Core 之後,EF Core 開發團隊開發了自己的 SQLite 程式套件 Microsoft.Data.Sqlite,其依賴 SQLitePCLRaw Bundle 套件,以提供不同平台(Windows/Linux/MacOS)所需的原生程式庫,以 SQLitePCLRaw.bundle_e_sqlite3 為例,它依賴 SQLitePCLRaw.core、SQLitePCLRaw.lib.e_sqlite、SQLitePCLRaw.provider.e_sqlite3,而 SQLitePCLRaw.lib.e_sqlite 就包含 alpine-x64、linux-arm、liunx-mips64、osx-arm、osx-x64、win-x64、win10-arm... 等近 20 種不同平台的程式庫,有 libe_sqlite3.so、libe_sqlite3.dylib、e_sqlite3.dll 各平台用的原生程式庫:

Microsoft.Data.Sqlite 預設使用 SQLitePCLRaw.bundle_e_sqlite3,但尚有 bundle_e_sqlcipher、bundle_green、bundle_sqlite3、bundle_winsqlite3、bundle_zetetic 等選擇,都出自同一個 Github 開源專案

有趣的問題來了,SQLitePCLRaw 由誰維護?作者 Eric Sink 是微軟 MVP,SQLitePCLRaw 的前身是 Codeplex 上由 Microsoft Open Tech 釋出的 SQLite Portable Class Library (SQLitePCL),所以 SQLitePCLRaw 不是微軟或 SQLite 官方的專案。但有一點很重要,SQLitePCL 扮演的只是橋樑角色,將 Microsoft.Data.SQLite 需要的 SQLite 方法透過統一介面對映到不同作業系統上的原生程式庫,除了官方版可能還有其他選擇,例如:

  • 在 iOS 上作業系統本身便有提供 SQLite 程式庫
  • Android 也內建 SQLite 程式庫,且在 Android N 前 App 就可以使用
  • 較新版 Windows 10 版本已開始內建 SQLite 程式庫
  • 有些人會選擇 SQLCipher 版或自己編譯的 SQLite 程式庫

有了這個概念,我們才能理解先前提到各種 Bundle 的意義:

  • bundle_e_sqlite3 - 內含 SQLitePCLRaw 專案編譯的原生程式庫(名為 e_sqlite3.*),原始碼來自 SQLite 官方,但版本可能不是最新的
  • bundle_e_sqlcipher - SQLitePCLRaw 專案編譯的 SQLCipher 版
  • bundle_green - 與 bundle_e_sqlite3 相同,但 iOS 改用作業系統內建版
  • bundle_sqlite3 - 使用 iOS/Android 內建程式庫或自行安裝官方 SQLite 程式庫
  • bundle_winsqlite3 - 使用 Windows 10 內建程式庫(winsqlite3.dll)
  • bundle_zetetic - 使用 Zetetic 提供的 SQLCipher 版(原生程式庫要自行安裝)

有趣的是,一開始微軟決定開發 Microsoft.Data.Sqlite 是因為 .NET Core 1.x 移除了許多 API,讓 System.Data.Sqlite 難以移植到 .NET Core 平台;而 .NET Core 2.x 改變策略,把 DataSet 等 API 又加回去,於是 System.Data.Sqlite 有了 .NET Standard 2.0 版,可在 .NET Core 2+/.NET 5+ 使用。而 Mircosoft.Data.Sqlite 則維持原先輕量級並以支援新一代資料庫存取方式的目標,對 ADO.NET 功能支援受限。在 .NET Core/5+ 要用 ADO.NET 方式寫程式,等於有兩種選擇。參考

回到 Quintos 的問題,答案是 - 如果用 EF Core 開發程式,它依賴 Microsoft.Data.SQLite,預設會使用 SQLitePCLRaw.bundle_e_sqlite3 內含由 SQLitePCLRaw 作者編譯的原生程式庫(原始碼來自 SQLite 官方);若要改用 Windows 10/iOS 內建的 SQLite 程式庫,需改參照不同 Bundle,如:

dotnet add package Microsoft.Data.Sqlite.Core
dotnet add package SQLitePCLRaw.bundle_winsqlite3

因此,除非特別參照特定 Bundle Package,.NET 6 程式預設是使用 SQLitePCLRaw 專案由 SQLite 官方原始碼編譯的原生程式庫,基本上也算官方版。

但如果不打算使用 EF Core,只用傳統 ADO.NET 方式存取資料庫,則有兩種選擇:微軟的 Microsoft.Data.Sqlite 或 SQLite 官方維護的 System.Data.Sqlite,後者功能對 ADO.NET 介面的支援較完整。但 Microsoft.Data.Sqlite 底層也是用 SQLite 官方寫的原生程式庫,效能會不會有明顯差異,就又是另一個有趣議題了。

2022-04-15 更新:原先結論有誤,感謝徐胖胖指正。對細節有興趣,推薦這篇專業剖析:[UWP] SQLite 的 NuGet package 的搭配 by 胖胖的點人生

Introduce to the concept of SQLitePCLRaw and the different bundles.


Comments

Be the first to post a comment

Post a comment