You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中如何使用Span<T>优化数据库二进制数据读取的性能?

优化方案

核心思路是全程用ReadOnlyMemory<byte>替代byte[]作为二进制数据的载体,利用内存视图的特性只传递缓冲区引用而非复制实际数据,仅在必须修改数据或者对接需要byte[]的旧API时才执行拷贝。

1. 数据读取阶段取消首次数组拷贝

原来的(byte[])reader["Photo"]会强制把SqlClient内部缓冲区的数据复制到新的byte数组,产生第一次不必要的拷贝。改成直接读取ReadOnlyMemory<byte>:

// 先获取字段序号,比字段名查找性能更好
int photoColOrdinal = reader.GetOrdinal("Photo");
DataAccess.Person person = new();
// 直接读取为ReadOnlyMemory<byte>,不会复制实际二进制数据
person.Photo = reader.GetFieldValue<ReadOnlyMemory<byte>>(photoColOrdinal);

注意这里需要把Person类的Photo属性从byte[]改成ReadOnlyMemory<byte>类型,如果后续需要修改数据可以替换为Memory<byte>。

2. 各层流转时避免数据拷贝

DTO的Photo属性同样定义为ReadOnlyMemory<byte>,赋值时直接传递内存视图即可:

// DTO定义
public class PersonDto
{
    public ReadOnlyMemory<byte> Photo { get; set; }
    // 其他属性
}

// 从数据访问实体赋值到DTO,仅复制Memory结构体(十几字节的小对象),不会复制二进制数据
PersonDto dto = new()
{
    Photo = person.Photo
};

如果需要截取二进制的部分内容,直接用Slice方法,返回的还是原数据的视图,不会产生拷贝:

// 取前100字节的视图,无拷贝
var header = dto.Photo.Slice(0, 100);

3. 业务规则处理阶段按需访问

如果业务处理只需要读取数据,直接转成Span<byte>访问,性能更高:

ReadOnlySpan<byte> photoSpan = dto.Photo.Span;
// 直接读取内容,比如验证文件头
if (photoSpan.Length >= 2 && photoSpan[0] == 0xFF && photoSpan[1] == 0xD8)
{
    // 确认是JPG格式
}

只有当你需要修改二进制内容,或者必须对接要求byte[]参数的旧API时,才调用ToArray()方法执行拷贝,尽可能推迟拷贝的发生时机,避免无意义的前置拷贝。

内容的提问来源于stack exchange,提问作者Sandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:54:04