`
isiqi
  • 浏览: 16622417 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

谈如何提高从数据库中读写二进制数据的效率并节省资源

阅读更多

写入:

这段摘至MSDN,一看就是翻译的,不是很通顺,但方法没有问题:)

将 BLOB 值写入 SQL Server 时节省资源

通过插入或更新带有字符串值或字节数组(取决于数据库中的字段类型)的字段,可以将二进制大对象 (BLOB) 写入数据库(请参见将 BLOB 值写入数据源)。但是,BLOB 可能相当大,因此在作为单个值写入时可能要使用大量的系统内存,从而降低应用程序的性能。

为减少写入 BLOB 值时使用的内存量,通常是将 BLOB 以“块”的形式写入数据库。以此方法将 BLOB 写入数据库的过程依赖于数据库的功能。

以下示例演示如何将 BLOB 以块的形式写入 SQL Server。该示例向 Northwind 数据库的 Employees 表添加了一个包含员工照片的新记录,该照片就是一个 BLOB。该示例使用 SQL Server 的 UPDATETEXT 函数将新添加的员工的照片以指定大小的块写入 Photo 字段。

UPDATETEXT 函数要求一个指向所更新的 BLOB 字段的指针。在此示例中,在添加新员工的记录后,将调用 SQL Server TEXTPTR 函数以返回一个指向新记录的 Photo 字段的指针。返回的指针值将作为输出参数传递回去。示例中的代码保留此指针,并在追加数据块时将其传递到 UPDATETEXT。

用于插入新员工记录和保留指向 Photo 字段的指针的 Transact-SQL 将在下例中显示(其中 @Identity 和 @Pointer 被标识为 SqlCommand 的输出参数)。

复制代码
INSERT INTO Employees (LastName, FirstName, Title, HireDate, ReportsTo, Photo)
Values(@LastName, @FirstName, @Title, @HireDate, @ReportsTo, 0x0)
SELECT @Identity = SCOPE_IDENTITY()
SELECT @Pointer = TEXTPTR(Photo) FROM Employees WHERE EmployeeID = @Identity

请注意,在 Photo 字段中插入了初始值 0x0(空)。这确保可以检索到新插入记录的 Photo 字段的指针值。但是,空值不会影响追加的数据块。

在保留指向新插入记录中的 Photo 字段的指针后,示例可以接着使用 SQL Server 的 UPDATETEXT 函数向 BLOB 字段追加数据块。UPDATETEXT 函数接受以下对象作为输入:字段标识符 (Employees.Photo)、指向 BLOB 字段的指针、表示 BLOB 中写入当前块的位置的偏移量值,以及要追加的数据块。以下代码示例显示 UPDATETEXT 函数的语法(其中 @Pointer、@Offset, 和 @Bytes 被标识为 SqlCommand 的输入参数)。

复制代码
UPDATETEXT Employees.Photo @Pointer @Offset 0 @Bytes

偏移量值由内存缓冲区的大小确定,而该大小取决于应用程序的需要。大的缓冲区写入 BLOB 的速度较快,但会使用更多的系统内存。此示例使用的缓冲区相当小,只有 128 字节。为第一个数据块分配的偏移量值为 0,然后偏移量值对每个连续块按缓冲区大小递增。

该示例按块从提供的文件路径中检索员工照片。它根据指定的缓冲区大小,将每个块读入一个字节数组。然后,将字节数组设置为 SqlCommand 的 @Bytes 输入参数的值。更新 @Offset 参数值并执行 SqlCommand 后,当前的字节块追加到员工记录的 Photo 字段中。

usingSystem;
usingSystem.Data;
usingSystem.Data.SqlClient;
usingSystem.IO;

publicclassEmployeeData
...{
publicstaticvoidMain()
...{
DateTimehireDate
=DateTime.Parse("4/27/98");
intnewID=AddEmployee("Smith","John","SalesRepresentative",hireDate,5,"smith.bmp");
Console.WriteLine(
"NewEmployeeadded.EmployeeID="+newID);
}


publicstaticintAddEmployee(stringlastName,stringfirstName,stringtitle,DateTimehireDate,intreportsTo,stringphotoFilePath)
...{
SqlConnectionconnection
=newSqlConnection("DataSource=localhost;IntegratedSecurity=SSPI;InitialCatalog=Northwind;");

SqlCommandaddEmp
=newSqlCommand("INSERTINTOEmployees(LastName,FirstName,Title,HireDate,ReportsTo,Photo)"+
"Values(@LastName,@FirstName,@Title,@HireDate,@ReportsTo,0x0);"+
"SELECT@Identity=SCOPE_IDENTITY();"+
"SELECT@Pointer=TEXTPTR(Photo)FROMEmployeesWHEREEmployeeID=@Identity",connection);

addEmp.Parameters.Add(
"@LastName",SqlDbType.NVarChar,20).Value=lastName;
addEmp.Parameters.Add(
"@FirstName",SqlDbType.NVarChar,10).Value=firstName;
addEmp.Parameters.Add(
"@Title",SqlDbType.NVarChar,30).Value=title;
addEmp.Parameters.Add(
"@HireDate",SqlDbType.DateTime).Value=hireDate;
addEmp.Parameters.Add(
"@ReportsTo",SqlDbType.Int).Value=reportsTo;

SqlParameteridParm
=addEmp.Parameters.Add("@Identity",SqlDbType.Int);
idParm.Direction
=ParameterDirection.Output;
SqlParameterptrParm
=addEmp.Parameters.Add("@Pointer",SqlDbType.Binary,16);
ptrParm.Direction
=ParameterDirection.Output;

connection.Open();

addEmp.ExecuteNonQuery();

intnewEmpID=(int)idParm.Value;

StorePhoto(photoFilePath,(
byte[])ptrParm.Value,connection);

connection.Close();

returnnewEmpID;
}


publicstaticvoidStorePhoto(stringfileName,byte[]pointer,SqlConnectionconnection)
...{
intbufferLen=128;//Thesizeofthe"chunks"oftheimage.

SqlCommandappendToPhoto
=newSqlCommand("UPDATETEXTEmployees.Photo@Pointer@Offset0@Bytes",connection);

SqlParameterptrParm
=appendToPhoto.Parameters.Add("@Pointer",SqlDbType.Binary,16);
ptrParm.Value
=pointer;
SqlParameterphotoParm
=appendToPhoto.Parameters.Add("@Bytes",SqlDbType.Image,bufferLen);
SqlParameteroffsetParm
=appendToPhoto.Parameters.Add("@Offset",SqlDbType.Int);
offsetParm.Value
=0;

//''''''''''''''''''''''''''''''''''
//Readtheimageinandwriteittothedatabase128(bufferLen)bytesatatime.
//TunebufferLenforbestperformance.Largervalueswritefaster,but
//usemoresystemresources.

FileStreamfs
=newFileStream(fileName,FileMode.Open,FileAccess.Read);
BinaryReaderbr
=newBinaryReader(fs);

byte[]buffer=br.ReadBytes(bufferLen);
intoffset_ctr=0;

while(buffer.Length>0)
...{
photoParm.Value
=buffer;
appendToPhoto.ExecuteNonQuery();
offset_ctr
+=bufferLen;
offsetParm.Value
=offset_ctr;
buffer
=br.ReadBytes(bufferLen);
}


br.Close();
fs.Close();
}

}



读取:

这是我自己写的读取的例子:)

/**////<summary>
///根据图片的Id获取图片的内容
///</summary>
///<paramname="photoId"></param>
///<returns></returns>

publicImageGetPhotoContentById(stringphotoId)
...{
SqlConnectionconn
=null;
SqlCommandcomm
=null;
SqlDataReaderreader
=null;

Imageimage
=null;
try
...{
conn
=newSqlConnection(_connectionString);
conn.Open();
comm
=conn.CreateCommand();
comm.CommandText
=_selectPhotoSQL;
comm.Parameters.Add(
"@id",SqlDbType.Int,4).Value=photoId;
//reader=comm.ExecuteReader();
reader=comm.ExecuteReader(CommandBehavior.SequentialAccess);
//Streamstream=null;
MemoryStreamstream=newMemoryStream();
if(reader.Read())
...{
//直接行读取
//stream=reader.GetSqlBytes(reader.GetOrdinal("photocontent")).Stream;
//byte[]bytes=reader["photocontent"]asbyte[];
//stream=newMemoryStream(bytes);

//改为块儿读取,以节省内存资源
intiOrdinal=reader.GetOrdinal("photocontent");
longdataIndex=0;
intbufferSize=1024;
byte[]outBuffer=newbyte[bufferSize];
BinaryWriterwriter
=newBinaryWriter(stream);

longretval=reader.GetBytes(iOrdinal,dataIndex,outBuffer,0,bufferSize);

while(retval==bufferSize)
...{
//stream.Write(outBuffer,0,bufferSize);

writer.Write(outBuffer);
writer.Flush();

dataIndex
+=bufferSize;
retval
=reader.GetBytes(iOrdinal,dataIndex,outBuffer,0,bufferSize);
}


writer.Write(outBuffer,
0,bufferSize-1);
writer.Flush();
//writer.Close();

}

try
...{
if(stream!=null)
image
=Image.FromStream(stream,true,true);
}

catch(ArgumentExceptione)
...{
thrownewException(e.Message);
}


returnimage;
}

catch(SqlExceptionex)
...{
thrownewException(ex.Message);
}

finally
...{
if(reader!=null)...{
reader.Close();
reader.Dispose();
}

if(comm!=null)...{
comm.Parameters.Clear();
comm.Dispose();
}

if(conn!=null)...{
conn.Close();
conn.Dispose();
}

}


}
分享到:
评论

相关推荐

    通过二进制数据流的方式,读写图片,把图片存入数据库

    本主题主要探讨如何利用二进制数据流来读取、写入图片,并将其安全地存入数据库,以及如何从数据库中读取并显示这些图片。 一、二进制数据流的理解 二进制数据流(Binary Data Stream)是一种处理原始二进制数据的...

    结构体序列化读写二进制文件类

    3. 块读操作:类似地,块读取允许程序按需读取数据,而不是一次性加载整个文件,从而节省内存资源并提高效率。 4. 错误处理:类可能包括检查文件是否损坏、确保数据完整性等错误处理机制。 5. 容错性:可能有备份...

    使用二进制存取用户头像

    "使用二进制存取用户头像"这个主题涉及到如何将图像数据以二进制形式存储并从数据库中检索,以提高数据传输速度和节省存储空间。下面将详细介绍这个过程及其相关知识点。 一、二进制数据存储 1. 图像文件格式:...

    图片存取 (二进制)

    1. 效率:二进制数据直接对应计算机内存和硬盘上的物理位,读写速度快。 2. 通用性:二进制数据不受文件格式限制,适用于多种环境和平台。 3. 数据完整性:二进制存储能更好地保留原始数据,减少因格式转换导致的...

    HYZ数据库文件读写控件

    1. 文件存储:HYZ数据库文件读写控件支持将各种类型的文件以二进制数据形式存储在数据库中,包括常见的图像、音频、文档等格式。这样不仅节省了磁盘空间,还能避免因文件路径变化导致的数据丢失问题。 2. 文件读取...

    Go-binpacker-一个二进制打包和解包器帮助用户构建定制的二进制流

    - **数据存储**:在数据库或其他持久化存储中,使用二进制格式可以节省存储空间,加快读写速度。 - **序列化/反序列化**:在需要将数据转换为可传递或可存储的形式时,如JSON、XML等,二进制格式通常更紧凑、更快。 ...

    向数据库中放置和取出文件

    在IT行业中,数据库不仅仅是用来存储结构化数据,如数字、字符串和日期,有时也需要存储非结构化数据,比如图片、文档和其他二进制大对象(BLOB)。标题“向数据库中放置和取出文件”涉及的就是如何在数据库系统中...

    把图片放到数据库中

    在关系型数据库中,图片通常被存储为BLOB类型的数据,这允许存储任何类型的二进制数据,包括图像文件。每个图片都会被转换成字节流并存储在数据库中。 **3. 图像数据的存储策略** - **直接存储**:将整个图像文件...

    数据库上传下载图片源代码

    - 数据发送:将二进制数据作为响应体发送给客户端,浏览器会自动解析并显示图片。 5. 文件路径存储与物理存储: 另一种常见方法是不直接存储图片二进制数据,而是存储图片的文件路径。这种方式节省数据库空间,但...

    2019秋电大数据库运维复习资料 数据库运维.pdf

    14. **中继日志文件**:中继日志记录了从主服务器接收到的更改,用于在从服务器上重放,其结构不同于二进制日志,可以自定义路径,并在I/O线程启动时创建。 15. **显示复制线程状态**:使用`SHOW SLAVE STATUS\G`...

    学习Oracle数据库基本数据类型.pdf

    Oracle会直接在数据库中存储这些大型数据,提供读写等操作。 9. **BFile**: BFile是一种外部LOB类型,数据实际存储在数据库外部,但可以通过数据库进行读取和查询,最大长度同样为4GB。BFile适用于需要存储在文件...

    Mysql LONGBLOB 类型存储二进制数据 (修改+调试+整理)

    在本文中,我们将探讨如何在MySQL中使用LONGBLOB类型来存储二进制数据,并通过C++编程进行插入操作,以及需要注意的一些配置调整。 首先,创建数据库和表结构是关键。在MySQL中,你可以执行以下SQL语句来创建名为`...

    图片存储到Access数据库中

    在IT领域,数据库是用于存储和管理数据的重要工具,而Access是Microsoft公司...在Java编程环境下,利用JDBC或Apache POI库可以方便地实现图片数据的读写,同时注意数据库设计和性能优化,以确保系统的稳定性和效率。

    C#图片格式传入数据库

    在C#编程中,将图片数据存储到数据库通常涉及到对图像进行编码,将其转化为二进制数据,然后存储在数据库的BLOB(Binary Large Object)字段中。这种做法允许我们以非结构化的方式存储大量的图像数据。以下是实现这...

    行业-24 我们写入数据库的一行数据,在磁盘上是怎么存储的.rar

    在这里,数据会被格式化并打包到数据库的最小存储单元——数据页(Data Page)中。一个数据页通常包含多行数据,以及一些元数据,比如页头信息,指示页的类型、状态和包含的数据行数。 每个数据行在数据页内占据...

    cachecloud-bin-1.2.tar.gz 二进制一键安装包,官方版1.2

    为了深入了解和使用CacheCloud,用户需要了解如何在Linux环境下操作命令行,解压并安装二进制包,以及可能涉及的网络配置、环境变量设置等。同时,官方文档或社区资源将提供详细的安装步骤和使用教程,以帮助用户更...

    MySQL数据库技巧MySQL优化之数据类型的使用

    MySQL数据库的优化是一个重要的主题,尤其在大数据量和高并发的场景下,合理选择数据类型对于提升查询效率和节省存储空间至关重要。以下是一些关于MySQL数据类型选择和优化的要点: 1. **选择最合适的最小数据类型*...

    GIS大讲堂SDEforOracle存储机制研究系列.doc

    在Oracle地理数据库中,BLOB(Binary Large Object)数据类型用于存储大块的二进制数据,如空间几何对象。BLOB的存储结构包括三部分:BLOB列、LOB段和LOB索引。BLOB列存储LOB定位器,这是一个指向实际数据的指针,...

    Sqlite大对象字段读写及数据流的解压缩

    在SQLite中存储大对象时,为了节省存储空间,我们可以先对数据进行压缩,再写入数据库,读取时进行解压缩。 以下是如何使用ZlibNet压缩和解压缩二进制数据的代码片段: ```csharp using ZlibNet; // 压缩数据 ...

    Access数据库压缩程序-源码.rar

    数据库压缩有助于节省存储空间,提高数据读取速度,并可能对数据库性能产生积极影响。 关于Access数据库的压缩,通常涉及以下知识点: 1. 数据库备份与压缩:在对Access数据库进行压缩前,通常需要先备份,以防止...

Global site tag (gtag.js) - Google Analytics