1. 从20,171倍性能差距看LLM生成代码的陷阱
上周我在测试一个号称"完全兼容SQLite"的Rust重写版数据库时,发现了一个令人震惊的事实:对100行数据的主键查询,这个LLM生成的版本比原版SQLite慢了整整20,171倍。这不是普通的性能差异,而是暴露了LLM生成代码的本质缺陷——它擅长生成"看起来合理"的代码,却无法保证代码的正确性和高效性。
作为从业15年的数据库工程师,我见过太多类似的案例。LLM生成的代码往往能通过编译、跑通测试用例,甚至在demo中表现良好,但在真实场景下却漏洞百出。这次测试的Rust版SQLite就是个典型例子:它拥有57.6万行代码(是原版的3.7倍),支持MVCC并发写入,API完全兼容,README写得专业漂亮...但就是慢得无法使用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 性能灾难的根源分析
2.1 缺失的ipk检查:从O(log n)到O(n²)的悲剧
在SQLite中,当表中有INTEGER PRIMARY KEY列时,该列会自动成为内部rowid的别名。这意味着WHERE id=5这样的查询可以直接走B-tree搜索,时间复杂度是O(log n)。这是SQLite查询优化器的基本设计,不是锦上添花的优化。
原版SQLite在where.c中有这样一行关键代码:
c复制if(iColumn==pIdx->pTable->iPKey){
iColumn = XN_ROWID;
}
这行代码将命名列转换为内部rowid,使VDBE执行引擎能使用高效的SeekRowid操作而非全表扫描。
然而在LLM生成的Rust版本中,虽然B-tree实现是正确的,table_seek函数也实现了标准二叉搜索,但查询规划器从未调用它!其is_rowid_ref()函数只识别三个魔法字符串:
rust复制fn is_rowid_ref(col_ref: &ColumnRef) -> bool {
let name = col_ref.column.to_ascii_lowercase();
name == "rowid" || name == "_rowid_" || name == "oid"
}
结果就是所有WHERE id=N的查询都走了全表扫描,时间复杂度
