当你看到"CRUD MVCC事务:1.2微秒"这个指标,你第一反应是哪种语言写的?C?Rust?
答案是 C#。
这个结果来自一个叫 Typhon 的项目——用 .NET/C# 编写的嵌入式 ACID 数据库引擎,作者是法国工程师 Loïc Baumann,有30年实时3D引擎和系统软件开发经验。他的目标很直接:在 .NET 生态里实现 1-2 微秒级事务提交延迟。
"大家都会告诉你,做高性能数据库引擎只能用 C、C++ 或 Rust。" Baumann 在博客里写道,"我选了 C#。"
现代 C# 已经不是你认识的那个 C# 了。
GC暂停问题:固定内存就解决了
GC 会产生 10ms 级别的暂停。对微秒级延迟来说,10ms 是 10000 倍的延迟预算,直接报废。
但 Typhon 的解决方案出奇地简单:用 GCHandle.Alloc(Pinned) 把页面缓存的内存固定死。GC 永远不会碰这块内存——不会扫描,不会移动,不会压缩。它就像 malloc 分配出来的原始字节一样,只是地址固定。
关键在于:只在真正重要的内存上固定,而不是把整个堆都 pin 住。页面缓存是 Typhon 的高频路径,事务操作全部落在这块固定内存上,GC 的影响因此被压制到最小。
内存布局:unsafe可以精确到字节
托管堆会压缩和移动对象。你无法保证 B+Tree 节点恰好对齐在缓存行边界上,无法保证页面缓存在事务执行到一半时不会被 GC 悄悄移走。
现代 C# 的解法:
// 控制每个字段的偏移量、填充、缓存行对齐
[StructLayout(Explicit)]
// 创建固定大小的内联数组
fixed byte[128]
_buffer;
// 裸指针和指针运算
unsafe { byte*
ptr = &data; }
Typhon 的 EntityRef 结构体是 96 字节的 ref struct,完全在栈上生存,永不逃逸到堆。零 GC 压力,零间接寻址。
SIMD指令:直接调CPU指令
这是最让人震惊的部分。
System.Runtime.Intrinsics 提供 Sse42.X64.Crc32、Vector256——直接对应 CPU 指令集中的具体指令。你写的是 C# 代码,JIT 编译出来的是一条 x86 crc32 指令。
//
Typhon 的
WAL 校验和计算
private static
uint ComputeSse42X64(
uint crc, ReadOnlySpan<byte> data) {
ulong crc64 = crc;
ref byte ptr = ref MemoryMarshal.GetReference(data);
//
直接调用 CPU 的 crc32 指令
crc64 = Sse42.X64.Crc32(crc64,
Unsafe.ReadUnaligned<ulong>(ref ptr));
return (uint)crc64;
}
每 8KB 页面只需约 1.3 微秒。运行时自动检测 CPU 是否支持 SSE4.2,不支持则自动 fallback。JIT 会把不支持的分支识别为死代码,在最终编译时完全消除。
零拷贝:直接指向内存页
EntityRef.Read<T>() 返回 ref readonly T,直接指向 pinned 内存页中的确切位置。
整个链路:方法调用 → slot 查找 → chunk ID → 页面缓存 → 指针算术 → 引用。没有拷贝,没有分配,零 GC 参与。
关键是 where T : unmanaged 约束——JIT 知道这个类型的内存布局是确定的,生成的就是指针算术,没有任何额外的运行时检查。
真正的瓶颈:内存访问模式,不是语言
来看一个数据。Ryzen 7950X 上,L1 缓存命中需要 1.4 纳秒。DRAM 访问(缓存未命中)需要 61-73 纳秒。差距 50:1。
也就是说,无论你用什么语言,只要你制造了缓存未命中,CPU 就要等上 250 个时钟周期。没有任何"零成本抽象"能弥补这个差距。
Typhon 的 B+Tree 节点被设计为 128 字节——恰好是两条缓存行的大小。在 Zen4 架构上,步幅预取器会自动预取第二条缓存行。这个设计让插入延迟降低了 53%,查询延迟降低了 30%。
选什么语言不重要,数据结构对缓存是否友好才重要。
一句话总结
性能的关键不是选 C、Rust 还是 C#,而是你的数据结构对缓存是否友好。现代 C# 完全有能力进入微秒级俱乐部——前提是你愿意去了解它的底层能力。
unsafe、ref struct、Constrained generics、System.Runtime.Intrinsics——这不是奇怪的边缘特性,这是 .NET 团队花了十年时间构建的系统编程基础设施。
真正值得投资的,是加深对内存层次和缓存局部性的理解。语言只是工具。
引用来源:Why I'm Building a Database Engine in C# by Loïc Baumann,2026年3月28日
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号