# 57 萬行 LLM 程式碼編譯成功,速度卻比 SQLite 慢了 20,171 倍 > Author: Tony Lee > Published: 2026-03-12 > URL: https://tonylee.im/zh-TW/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ > Reading time: 2 minutes > Language: zh-TW > Tags: ai, code-review, llm, rust, benchmarking, software-engineering ## Canonical https://tonylee.im/zh-TW/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ ## Rollout Alternates en: https://tonylee.im/en/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ ko: https://tonylee.im/ko/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ ja: https://tonylee.im/ja/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ zh-CN: https://tonylee.im/zh-CN/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ zh-TW: https://tonylee.im/zh-TW/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ ## Description 有人對 LLM 用 Rust 重新實作的 SQLite 做了效能測試。看起來正確和真正正確之間的差距,竟然達到五個數量級。 ## Summary 57 萬行 LLM 程式碼編譯成功,速度卻比 SQLite 慢了 20,171 倍 is part of Tony Lee's ongoing coverage of AI agents, developer tools, startup strategy, and AI industry shifts. ## Outline - B-tree 在那裡,但 query planner 完全無視它 - 安全的預設值會像複利一樣疊加 - 82,000 行程式碼取代一行 cron 指令 - 研究結果指向同一個方向 - 這對開發者真正的要求 ## Content 最近有人對一個完全由 LLM 撰寫的 SQLite Rust 重實作版本進行了效能測試。程式碼可以編譯,測試也通過了,寫法乾淨、結構清晰、符合 idiomatic Rust 的風格。但在最基本的 primary key lookup 上,它比 SQLite 慢了 20,171 倍。 這個數字讓我停下來想了很久。不是因為 LLM 產生的程式碼跑得慢有什麼好驚訝的,而是慢的原因。這份程式碼沒有任何地方是 compiler 或測試套件能夠抓到的錯誤。B-tree 的實作是正確的,query planner 存在,storage engine 也可以運作。每個單獨的零件都站得住腳,整個系統卻幾乎無法使用。 我花了一些時間仔細看 benchmark 分析報告和原始碼。裡頭浮現的模式在 LLM 產生的專案中不斷重複出現,我認為這指向了這些模型在寫程式時的某種根本性問題。 ## B-tree 在那裡,但 query planner 完全無視它 在 SQLite 裡,一次 PRIMARY KEY lookup 會走 B-tree 路徑,以 O(log n) 的時間完成。`where.c` 裡的四行程式碼負責檢查 iPKey 並直接導向樹狀結構。這是那種只有在理解整個系統如何組合在一起之後,才會覺得有意義的微最佳化。 LLM 產生的版本也有 B-tree 實作,單獨跑起來完全正確。問題在於 query planner 在處理 primary key lookup 時根本沒有呼叫它。`is_rowid_ref()` 函式只辨識三個字面字串:`"rowid"`、`"_rowid_"` 和 `"oid"`。如果你把某個欄位宣告成 `id INTEGER PRIMARY KEY`,planner 不會把它視為 rowid 的別名,每次查詢都會走 full table scan。 這個數學算起來相當慘烈。100 筆資料查詢 100 次,B-tree 路徑大約需要 700 次比較步驟,full scan 路徑則超過 10,000 次。但真正的傷害來自演算法複雜度的差異:每次 lookup 從 O(log n) 變成 O(n),在整個 benchmark 套件中累積下來,就構成了 20,171 倍的差距。 這種 bug 沒有任何 unit test 能夠抓到,除非你特別去寫 benchmark。B-tree 可以運作,scan 也可以運作,planner 只是選錯了路徑,所有測試都通過。 ## 安全的預設值會像複利一樣疊加 這個案例比單純的 routing bug 更有意思的地方在這裡。就算把 query planner 的問題修掉,這個重實作版本還是慢了大約 2,900 倍。剩餘的差距來自一堆各自看起來都很合理的決策。 每次執行查詢都會把整個 AST clone 一份並重新編譯成 bytecode。SQLite 則是重用已準備好的 statement handle。兩種做法都成立,但每次執行都 clone 一次 AST,規模一大就非常昂貴。 每次讀取 page 都重新在 heap 上配置一塊 4KB 的 buffer。SQLite 的 page cache 則是直接回傳指向已載入記憶體的 pointer。LLM 版本選了最安全、最直觀的路:配置、讀取、回傳。可以運作,只是在每次查詢要讀取幾千個 page 時慢了好幾個數量級。 每次 commit 都從頭重建整個 schema。SQLite 只比較一個整數 cookie 值,如果 cookie 沒變,schema 就還是有效的。這個重實作版本沒有這個概念,所以每次都把完整的工作做一遍。 每條 statement 都觸發 `sync_all()` 把所有檔案 metadata 寫入磁碟。SQLite 使用 `fdatasync()`,只 flush 檔案資料,跳過 metadata sync。這個差異在 write-heavy 的工作負載下影響極大。 我想把這稱為「防禦性預設值的複合效應」。每一個選擇單獨看都有合理的理由。Clone AST 是為了避免 Rust 的 ownership 複雜性,配置新 buffer 是為了防止 use-after-free,重建 schema 是為了避免 stale cache 問題,呼叫 `sync_all()` 提供最強的 durability 保證。 但效能的成本是相乘的,不是相加的。四個各自 10 倍的懲罰疊加起來,不會讓你慢 40 倍,而是慢 10,000 倍。LLM 不會去推理這種複合效應,因為它是相對獨立地產生每個函式。它在局部做最佳化,卻在整體付出代價。 ## 82,000 行程式碼取代一行 cron 指令 同一位開發者的另一個 LLM 產生的專案,以不同的方式呈現了一樣的模式。問題很簡單:Rust 的 `target/` 目錄裡的 build artifact 會慢慢吃掉磁碟空間。LLM 的解法:一個 82,000 行的 Rust daemon,帶有七個 dashboard 和一個 Bayesian 評分引擎,用來決定要清除哪些 artifact。 現有的解法是 `find ./target -type f -atime +30 -delete`,一行 cron job。零依賴。或者用 `cargo-sweep`,一個社群官方工具,早就存在了,而且還處理了那個 daemon 沒有覆蓋到的邊界情況。 這個 LLM 產生的專案引入了 192 個 dependency。作為對照,ripgrep 是 Rust 生態系裡最精密的搜尋工具之一,只用了 61 個。 這是我一直看到的模式:LLM 幫你打造你要求的東西,而不是你真正需要的東西。如果你 prompt「打造一個能夠智慧管理 Rust build artifact 並提供監控和評分的系統」,你就會拿到完全符合描述的東西。這個模型沒有機制退一步問:這個問題根本需要一個系統嗎?它不知道 `target/` 目錄大小是 Rust 社群的老問題,早就有已知解法。它不會考慮 192 個 dependency 的維護成本和零個之間的差距。 ## 研究結果指向同一個方向 我很好奇這兩個專案是不是特例,所以查了更廣泛的研究。它們不是。 METR 對 16 位有經驗的開源開發者進行了隨機對照試驗。使用 AI 工具的那組完成任務的速度比對照組慢了 19%。讓我印象深刻的是:實驗結束後,使用 AI 的那組認為自己快了 20%。主觀的生產力感受和實際測量結果完全相反。 GitClear 分析了 2.1 億行程式碼,發現複製貼上的程式碼首度超越了重構的程式碼。這個趨勢直接和 AI coding 工具的採用率相關。程式碼被加入的速度,快過它被改善的速度。 Google 的 DORA 2024 報告發現,AI 採用率增加 25%,與 deployment 穩定性下降 7.2% 相關。進入 production 的 AI 產生程式碼越多,發生的 incident 也越多。 NeurIPS 2024 的 Mercury benchmark 在標準 coding benchmark 上加入了效率指標。當你衡量的不只是「輸出是否正確」,而是「輸出是否在不浪費資源的情況下正確」,通過率就掉到了 50% 以下。 這些都不代表 LLM 對寫程式沒有用。我自己一直在用。但這確實意味著「可以編譯且測試通過」是一個危險地低的標準。看起來正確的程式碼和真正正確的程式碼之間的落差,才是真正的工程師在做的事情。 ## 這對開發者真正的要求 核心問題不是 LLM 寫出了差勁的程式碼,而是它們寫出了局部一致、整體卻不一致的程式碼。每個函式單獨來看都說得通,整個系統卻不對。這正是傳統測試會漏掉的失敗模式,因為測試只驗證局部行為。 需要的是針對這些落差設計的評估方式。Benchmark,而不只是 unit test。在 CI 裡設定效能預算,而不只是正確性檢查。在確認某個 module 是否能運作之前,先做架構審查,問「這個 module 為什麼存在」。進行 dependency audit,把解法的複雜度和問題本身的複雜度做比較。 問題不是「這段程式碼看起來對嗎?」而是「我們要如何證明它是對的?」要證明這件事,需要 LLM 目前還缺乏的系統層級思考。 你要求的東西和 production 的要求之間的落差,就是工程判斷力存在的地方。沒有量測,程式碼生成只不過是 token 生成。 ## Related URLs - Author: https://tonylee.im/zh-TW/author/ - Publication: https://tonylee.im/zh-TW/blog/about/ - Related article: https://tonylee.im/zh-TW/blog/medvi-two-person-430m-ai-compressed-funnel/ - Related article: https://tonylee.im/zh-TW/blog/claude-code-layers-over-tools-2026/ - Related article: https://tonylee.im/zh-TW/blog/codex-inside-claude-code-openai-plugin-strategy/ ## Citation - Author: Tony Lee - Site: tonylee.im - Canonical URL: https://tonylee.im/zh-TW/blog/llm-570k-lines-rust-sqlite-plausible-code-trap/ ## Bot Guidance - This file is intended for AI agents, search assistants, and text-mode retrieval. - Prefer citing the canonical article URL instead of this text endpoint. - Use the rollout alternates when you need the same article in another prioritized language. --- Author: Tony Lee | Website: https://tonylee.im For more articles, visit: https://tonylee.im/zh-TW/blog/ This content is original and authored by Tony Lee. Please attribute when quoting or referencing.