小巧。快速。可靠。
任選三項。

SQLite 作為應用程式檔案格式

執行摘要

具有定義架構的 SQLite 資料庫檔案通常會成為絕佳的應用程式檔案格式。以下列出十二個原因說明為何如此

  1. 簡化應用程式開發
  2. 單一檔案文件
  3. 高階查詢語言
  4. 可存取的內容
  5. 跨平台
  6. 原子交易
  7. 增量和持續更新
  8. 易於擴充
  9. 效能
  10. 多個程序同時使用
  11. 多種程式語言
  12. 更好的應用程式

在更仔細考量「應用程式檔案格式」的意義後,以下將更詳細地說明每一點。另請參閱此白皮書的簡短版本

什麼是應用程式檔案格式?

「應用程式檔案格式」是用於將應用程式狀態持續儲存在磁碟或在程式之間交換資訊的檔案格式。目前使用中的應用程式檔案格式有數千種。以下僅列出幾個範例

我們區分「檔案格式」和「應用程式格式」。檔案格式用於儲存單一物件。因此,例如 GIF 或 JPEG 檔案儲存單一影像,而 XHTML 檔案儲存文字,所以這些是「檔案格式」,而不是「應用程式格式」。相反地,EPUB 檔案儲存文字和影像(包含 XHTML 和 GIF/JPEG 檔案),因此它被視為「應用程式格式」。本文探討「應用程式格式」。

檔案格式和應用程式格式之間的界線很模糊。本文稱 JPEG 為檔案格式,但對於影像編輯器而言,JPEG 可能被視為應用程式格式。這在很大程度上取決於脈絡。對於本文,我們假設檔案格式儲存單一物件,而應用程式格式儲存許多不同的物件及其彼此之間的關係。

大多數應用程式格式都屬於下列三種類別之一

  1. 完全自訂格式。自訂格式專門設計給單一應用程式。DOC、DWG、PDF、XLS 和 PPT 是自訂格式的範例。自訂格式通常包含在單一檔案中,以方便傳輸。它們通常也是二進位的,儘管 DWG 格式是一個顯著的例外。自訂檔案格式需要專門的應用程式程式碼才能讀取和寫入,而且通常無法從常見的工具(例如 unix 命令列程式和文字編輯器)存取。換句話說,自訂格式通常是「不透明的二進位資料」。要存取自訂應用程式檔案格式的內容,需要一個專門設計來讀取和/或寫入該格式的工具。

  2. 檔案堆疊格式。有時應用程式狀態會儲存在檔案階層中。Git 就是一個很好的例子,儘管這種現象經常發生在一次性及客製化應用程式中。檔案堆疊格式基本上將檔案系統用作鍵值資料庫,將小塊資訊儲存在個別檔案中。這帶來一個好處,讓一般實用程式(例如文字編輯器或「awk」或「grep」)更容易存取內容。但即使檔案堆疊格式中的許多檔案都很容易讀取,通常還是有些檔案有自己的自訂格式(例如:Git「封包檔案」),因此是「不透明二進位大物件」,無法在沒有專門工具的情況下讀取或寫入。將檔案堆疊從一個地方或機器移到另一個地方,也比移動單一檔案不方便許多。例如,很難將檔案堆疊文件製作成電子郵件附件。最後,檔案堆疊格式破壞了「文件隱喻」:使用者無法指出一個檔案是「文件」。

  3. 包裝式檔案堆疊格式。有些應用程式使用檔案堆疊,然後將其封裝到某種單一檔案容器中,通常是 ZIP 檔案。EPUB、ODT 和 ODP 就是這種方法的範例。EPUB 書籍實際上只是一個 ZIP 檔案,其中包含用於書籍章節文字的各種 XHTML 檔案、用於美術作品的 GIF 和 JPEG 影像,以及一個專門的目錄檔案,告訴電子書閱讀器所有 XML 和影像檔案如何組合在一起。OpenOffice 文件 (ODT 和 ODP) 也是 ZIP 檔案,其中包含 XML 和影像,代表其內容,以及顯示組成部分之間相互關係的「目錄」檔案。

    包裝式堆疊檔案格式是一種自訂檔案格式和純堆疊檔案格式之間的折衷方案。包裝式堆疊檔案格式並非像自訂格式一樣是不透明的二進制大型物件,因為組成部分仍然可以使用任何常見的 ZIP 壓縮檔存取,但由於仍然需要 ZIP 壓縮檔,且通常無法在檔案階層中使用「尋找」等命令列工具,因此格式並不像純堆疊檔案格式一樣容易存取。另一方面,包裝式堆疊檔案格式確實保留了文件隱喻,將所有內容放入單一磁碟檔案中。而且由於經過壓縮,包裝式堆疊檔案格式往往更為精簡。

    與自訂檔案格式一樣,與純堆疊檔案格式不同,包裝式堆疊檔案格式並不容易編輯,因為通常必須重新撰寫整個檔案才能變更任何組成部分。

本文的目的是主張採用第四種新的應用程式檔案格式類別:SQLite 資料庫檔案。

SQLite 作為應用程式檔案格式

任何可以在堆疊檔案中記錄的應用程式狀態也可以使用類似這樣的簡單金鑰/值架構記錄在 SQLite 資料庫中

CREATE TABLE files(filename TEXT PRIMARY KEY, content BLOB);
如果內容經過壓縮,則此類 SQLite 檔案 資料庫的 大小 (±1%) 與等效的 ZIP 檔案相同,而且具有能夠更新個別「檔案」而不重新撰寫整個文件的優點。

但 SQLite 資料庫並不僅限於堆疊檔案資料庫的簡單鍵/值結構。SQLite 資料庫可以有數十個、數百個或數千個不同的表格,每個表格有數十個、數百個或數千個欄位,每個欄位有不同的資料類型、約束和特定意義,全部互相交叉參照,適當地自動建立索引以快速擷取,並全部有效率且緊密地儲存在單一磁碟檔案中。而且,所有這些結構都由 SQL 架構簡潔地記錄下來,供人類使用。

換句話說,SQLite 資料庫可以執行堆疊檔案或包裝堆疊檔案格式可以執行的所有功能,以及更多功能,而且更清晰。SQLite 資料庫比鍵/值檔案系統或 ZIP 檔案更通用的容器。(有關詳細範例,請參閱 OpenOffice 案例研究。)

理論上,可以使用自訂檔案格式來達成 SQLite 資料庫的效能。但任何與關聯式資料庫一樣具表現力的自訂檔案格式,可能需要龐大的設計規格和數十萬或數百萬行程式碼才能實作。而且,最終結果將會是一個「不透明二進位大型物件」,無法使用特殊工具存取。

因此,與其他方法相比,使用 SQLite 資料庫作為應用程式檔案格式具有明顯的優點。以下是其中一些優點,逐一列舉並說明

  1. 簡化的應用程式開發。讀取或寫入應用程式檔案時,不需要新的程式碼。只要連結至 SQLite 函式庫,或將 單一的「sqlite3.c」原始檔 與應用程式的其他 C 程式碼包含在一起,SQLite 便會處理所有應用程式檔案的 I/O。這可以將應用程式程式碼的大小減少數千行,並在開發和維護成本上節省相應的費用。

    SQLite 是世界上 使用最廣泛 的軟體函式庫之一。每天在智慧型手機、小工具和桌面應用程式中實際使用數十億個 SQLite 資料庫檔案。SQLite 經過 仔細測試,並證明其可靠性。它不是需要大量調整或除錯的元件,讓開發人員可以專注於應用程式邏輯。

  2. 單一檔案文件。SQLite 資料庫包含在單一檔案中,可以輕鬆地複製、移動或附加。保留了「文件」的隱喻。

    SQLite 沒有任何檔案命名需求,因此應用程式可以使用任何自訂檔案副檔名,以協助將檔案識別為「屬於」該應用程式。SQLite 資料庫檔案在其標頭中包含一個 4 位元組的 應用程式 ID,可以設定為應用程式定義的值,然後用於識別文件「類型」以供實用程式使用,例如 file(1),進一步增強文件隱喻。

  3. 高階查詢語言。SQLite 是一個完整的關聯式資料庫引擎,這表示應用程式可以使用高階查詢來存取內容。應用程式開發人員不需要花時間思考「如何」從文件擷取他們需要的資訊。開發人員會撰寫 SQL 來表達他們想要「哪些」資訊,並讓資料庫引擎找出最佳的擷取內容方式。這有助於開發人員「抬頭挺胸」地運作,並專注於解決使用者的問題,並避免花時間「埋頭苦幹」地擺弄低階檔案格式的詳細資料。

    堆疊檔案格式可以視為一個鍵值資料庫。鍵值資料庫比完全沒有資料庫好。但如果沒有交易、索引、高階查詢語言或適當的架構,使用鍵值資料庫會比使用關聯式資料庫困難許多,而且更容易出錯。

  4. 可存取的內容。儲存在 SQLite 資料庫檔案中的資訊可以使用常見的開放原始碼命令列工具存取,這些工具已預設安裝在 Mac 和 Linux 系統上,而且可以在 Windows 上作為獨立的 EXE 檔案免費取得。與自訂檔案格式不同,不需要應用程式特定的程式來讀取或寫入 SQLite 資料庫中的內容。SQLite 資料庫檔案並非不透明的二進位大物件。雖然像文字編輯器或「grep」或「awk」這類的命令列工具無法用於 SQLite 資料庫,但 SQL 查詢語言是一種更強大且方便的方式來檢查內容,因此無法使用「grep」和「awk」等工具並不會被視為損失。

    SQLite 資料庫是一種定義良好且有良好文件記載的檔案格式,廣泛使用於數百萬個應用程式中,而且向後相容於 2004 年推出的版本,並承諾在未來數十年內持續相容。SQLite 資料庫檔案的長壽命對客製化應用程式來說特別重要,因為它允許在未來很長一段時間內存取文件內容,即使原始應用程式的所有痕跡都已消失。資料比程式碼更長壽。SQLite 資料庫被美國國會圖書館推薦為長期保存數位內容的儲存格式。

  5. 跨平台。SQLite 資料庫檔案可以在 32 位元和 64 位元機器、大端序和小端序架構、以及各種 Windows 和類 Unix 作業系統之間移植。使用 SQLite 應用程式檔案格式的應用程式可以儲存二進位數字資料,而不用擔心整數或浮點數的位元組順序。文字內容可以 UTF-8、UTF-16LE 或 UTF-16BE 讀取或寫入,而 SQLite 會自動執行必要的即時轉換。

  6. 原子交易。寫入 SQLite 資料庫是原子的。它們會完全發生或根本不會發生,即使在系統崩潰或停電期間也是如此。因此,不會有損毀文件的危險,因為在寫入變更到磁碟的同時,電源恰好中斷。

    SQLite 是交易性的,表示可以將多個變更分組在一起,以便它們全部發生或都不發生,並且可以在提交之前發現問題時將變更回滾。這允許應用程式逐步進行變更,然後在將變更提交到磁碟之前對結果資料執行各種健全性和一致性檢查。Fossil DVCS 使用此技術來驗證在每次變更之前沒有遺失任何儲存庫記錄。

  7. 增量和連續更新。寫入 SQLite 資料庫檔案時,只有實際變更的檔案部分會寫入磁碟。這使得寫入發生得更快,並節省 SSD 的磨損。這比自訂和封裝的堆疊檔案格式有很大的優勢,這兩種格式通常需要重寫整個文件才能變更一個位元組。純堆疊檔案格式也可以在某種程度上進行增量更新,儘管堆疊檔案格式(單一檔案)的寫入顆粒度通常比 SQLite(單一頁面)更大。

    SQLite 也支援連續更新。它不會在記憶體中收集變更,然後只在檔案/儲存動作時將它們寫入磁碟,而是會在變更發生時將它們寫回磁碟。這可以避免在系統崩潰或電源故障時遺失工作。可以使用觸發器管理的自動復原/重做堆疊可以保存在磁碟資料庫中,這表示復原/重做可以在會話邊界之間發生。

  8. 易於擴充。隨著應用程式的成長,只需將新表格新增到架構或將新欄位新增到現有表格,就可以將新功能新增到 SQLite 應用程式檔案格式。新增欄位或表格不會變更先前查詢的意義,因此只要適度注意確保保留舊有欄位和表格的意義,就能維持向後相容性。

    當然,也可以擴充自訂或堆疊檔案格式,但通常難度高很多。如果新增索引,則必須找到並修改所有變更對應表格的應用程式程式碼,以保持這些索引為最新狀態。如果新增欄位,則必須找到並修改所有存取對應表格的應用程式程式碼,以考量新欄位。

  9. 效能。在許多情況下,SQLite 應用程式檔案格式會比堆疊式檔案格式或自訂格式更快。除了原始讀寫速度較快之外,SQLite 通常還能大幅縮短啟動時間,因為應用程式不必將整個文件讀取並解析至記憶體中,而是可以執行查詢,僅擷取初始畫面所需的資訊。隨著應用程式執行,它只需要載入繪製下一個畫面的所需資料,並可以捨棄不再使用的先前畫面資訊。這有助於控制應用程式的記憶體使用量。

    堆疊式檔案格式可以像 SQLite 一樣逐步讀取。但許多開發人員會驚訝地發現,SQLite 可以從資料庫讀取和寫入較小的 BLOB(大小小於約 100KB)的速度比從檔案系統中讀取或寫入相同的 BLOB 作為個別檔案的速度更快。(請參閱比檔案系統快 35%內部 BLOB 與外部 BLOB以取得更多資訊。)操作關聯式資料庫引擎會產生一些額外負擔,但不要假設直接檔案 I/O 會比 SQLite 資料庫 I/O 更快,因為通常並非如此。

    無論在何種情況下,如果 SQLite 應用程式出現效能問題,通常可以透過在架構中新增一或兩個CREATE INDEX陳述式,或執行一次ANALYZE,而無需變更任何一行應用程式程式碼,來解決這些問題。但是,如果效能問題發生在自訂或堆疊式檔案格式中,修正方法通常需要大幅變更應用程式程式碼,才能新增和維護新的索引,或使用不同的演算法來擷取資訊。

  10. 多個程序同時使用。 SQLite 會自動協調多個執行緒和/或程序同時存取同一個文件。兩個或以上的應用程式可以同時連線並從同一個文件讀取。寫入會序列化,但由於寫入通常只需要幾毫秒,因此應用程式只需輪流寫入即可。SQLite 會自動確保文件的低階格式不會損毀。相比之下,使用自訂格式或堆疊檔案格式來達成相同目標,則需要應用程式提供廣泛的支援。而支援並行的應用程式邏輯是出了名的容易出錯。

  11. 多種程式語言。儘管 SQLite 本身是用 ANSI-C 編寫的,但幾乎所有你能想到的其他程式語言都存在介面:C++、C#、Objective-C、Java、Tcl、Perl、Python、Ruby、Erlang、JavaScript 等。因此,程式設計人員可以使用他們最擅長且最符合專案需求的語言進行開發。

    SQLite 應用程式檔案格式非常適合有許多獨立程式組成的集合或「聯盟」的情況,這些程式通常是用不同的語言編寫的,而且是由不同的開發團隊編寫的。這在研究或實驗室環境中很常見,其中一個團隊負責資料擷取,而其他團隊負責分析的不同階段。每個團隊可以使用他們最擅長的硬體、作業系統、程式語言和開發方法,只要所有程式都使用具有共同架構的 SQLite 資料庫,它們就可以互通作業。

  12. 更好的應用程式。如果應用程式檔案格式是 SQLite 資料庫,則該檔案格式的完整文件包含資料庫架構,可能還有關於每個表格和欄位代表什麼的幾個額外字詞。另一方面,自訂檔案格式的說明通常會長達數百頁。堆疊檔案格式雖然比完全自訂格式簡單且容易說明得多,但仍然比 SQL 架構傾印大且複雜得多,因為仍然必須說明個別檔案的名稱和格式。

    這一點並非微不足道。一種清晰、簡潔且易於理解的檔案格式是任何應用程式設計中至關重要的一部分。電腦科學史上最暢銷的書籍之一,弗雷德·布魯克斯在《人月神話》中說道

    表示法是電腦程式設計的精髓。
    ...
    展示你的流程圖,隱藏你的表格,而我將繼續感到困惑。展示你的表格,而我通常不需要你的流程圖;它們將顯而易見。

    羅伯·派克在他的《程式設計規則》中以這種方式表達了同樣的想法

    資料主宰一切。如果你選擇了正確的資料結構並組織好所有內容,那麼演算法幾乎總是顯而易見的。資料結構,而非演算法,是程式設計的核心。

    李納斯·托瓦茲在 2006 年 6 月 27 日的 Git 郵件列表中使用不同的字詞表達了大致相同的意思

    糟糕的程式設計師擔心程式碼。優秀的程式設計師擔心資料結構及其關係。

    重點在於:SQL 資料庫結構幾乎總是能更出色地定義和組織表格、資料結構及其關係。而擁有清晰、簡潔且定義良好的表示法幾乎總能產生效能更好的應用程式,且問題更少,開發和維護也更輕鬆。

結論

SQLite 並非適用於所有情況的完美應用程式檔案格式。但在許多情況下,SQLite 是遠比自訂檔案格式、一堆檔案或包裝成一堆檔案更好的選擇。SQLite 是一種高階、穩定、可靠、跨平台、廣泛部署、可擴充、效能良好、可存取、並行的檔案格式。在您下一次應用程式設計中,它值得您考慮作為標準檔案格式。

此頁面最後修改於 2022-01-08 05:02:57 UTC