为不同目的存储图像的最佳方法(关于数据库设计)是什么?
我有一堆用户照片,另外还有五套不同的照片(例如用户照片,但与用户照片没有关联)。
将所有照片存储在单个数据库表中并尝试从该表中引用它们是最好的办法,还是为每组照片创建不同的表最好?
我可以看到创建多个表的好处之一,那就是级联删除功能,用于在删除主要对象时删除照片。
还有其他方面需要考虑吗?
另一个例子可能是地址。用户可以有一个地址,但是公司或位置也可以。为所有地址创建一个表,并尝试使用某种索引表来引用哪个地址属于哪个对象或具有不同的表,从而消除该问题。
注意:现在ancient,此答案是正确的,我建议您将图像上传到Amazon S3,Google Cloud Storage或Azure Blob存储帐户,并将ID存储在数据库中。将How to model a Photo storage database仍然是相关的。
ancient
How to model a Photo storage database
在SQL Server中存储大量的二进制数据并不是一个好方法。它使您的数据库备份非常庞大,并且性能通常不高。存储 文件 通常是在 文件 系统上完成的。Sql Server 2008具有对的开箱即用支持FILESTREAM。Microsoft记录了使用 FileStream 的情况,如下所示
FILESTREAM
以您的情况,我认为所有观点都是有效的。
要FILESTREAM在服务器上启用支持,请使用以下语句。
EXEC sp_configure filestream_access_level, 2 RECONFIGURE
要获得链接到数据库的文件流文件组,请创建
ALTER DATABASE ImageDB ADD FILEGROUP ImageGroup CONTAINS FILESTREAM ALTER DATABASE ImageDB ADD FILE ( NAME = 'ImageStream', FILENAME = 'C:\Data\Images\ImageStream.ndf') TO FILEGROUP TodaysPhotoShoot
下一步是使用文件流存储在数据库中获取数据:
CREATE TABLE Images ( [Id] [uniqueidentifier] ROWGUIDCOL NOT NULL PRIMARY KEY, [CreationDate] DATETIME NOT NULL, [ImageFile] VARBINARY(MAX) FILESTREAM NULL )
为了Filestream工作,您不仅需要FILESTREAM表中字段上的ROWGUIDCOL属性,还需要具有该属性的字段。
Filestream
ROWGUIDCOL
现在要在此表中插入数据,可以使用TSQL:
using(var conn = new SqlConnection(connString)) using(var cmd = new SqlCommand("INSERT INTO Images VALUES (@id, @date, cast(@image as varbinary(max))", conn)) { cmd.Parameters.AddRange(new { new SqlParameter("id", SqlDbType.UniqueIdentifier).Value = uId, new SqlParameter("date", SqlDbType.DateTime).Value = creationDate, new SqlParameter("image", SqlDbType.varbinary).Value = imageFile, }); conn.Open cmd.ExecuteScalar(); }
SqlFileStream
还存在一种直接使用Win32在磁盘上获取文件数据的方法。这为您提供了SqlFileStream继承自的流式访问IO.Stream。
IO.Stream
使用win32插入数据可以通过以下代码完成:
public void InsertImage(string connString, Guid uId, DateTime creationDate, byte[] fileContent) { using (var conn = new SqlConnection(connString)) using (var cmd = new SqlCommand(@"INSERT INTO Images VALUES (@id, @date, cast(@image as varbinary(max)) output INSERTED.Image.PathName()" , conn)) { conn.Open(); using (var transaction = conn.BeginTransaction()) { cmd.Transaction = transaction; cmd.Parameters.AddRange( new[] { new SqlParameter("id", SqlDbType.UniqueIdentifier).Value = uId, new SqlParameter("date", SqlDbType.DateTime).Value = creationDate, new SqlParameter("image", SqlDbType.VarBinary).Value = null } ); var path = (string)cmd.ExecuteScalar(); cmd.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()"; var context = (byte[])cmd.ExecuteScalar(); using (var stream = new SqlFileStream(path, context, FileAccess.ReadWrite)) { stream.Write(fileContent, 0, fileContent.Length); } transaction.Commit(); } }
使用文件流方法来存储图像时,表非常狭窄,这对性能很有好处,因为每个8K数据页可以存储许多记录。我将使用以下模型:
CREATE TABLE Images ( Id uniqueidentifier ROWGUIDCOL NOT NULL PRIMARY KEY, ImageSet INTEGER NOT NULL REFERENCES ImageSets, ImageFile VARBINARY(MAX) FILESTREAM NULL ) CREATE TABLE ImageSets ( ImageSet INTEGER NOT NULL PRIMARY KEY, SetName nvarchar(500) NOT NULL, Author INTEGER NOT NULL REFERENCES Users(USerId) ) CREATE TABLE Users ( UserId integer not null primary key, UserName nvarchar(500), AddressId integer not null REFERENCES Addresses ) CREATE TABLE Organsations ( OrganisationId integer not null primary key OrganisationName nvarchar(500), AddressId integer not null REFERENCES Addresses ) CREATE TABLE Addresses ( AddressId integer not null primary key, Type nvarchar(10), Street nvarchar(500), ZipCode nvarchar(50), City nvarchar(500), ) CREATE TABLE OrganisationMembers ( OrganisationId integer not null REFERENCES Organisations, UserId integer not null REFERENCES Users, PRIMARY KEY (UserId, OrganisationId) ) CREATE NONCLUSTERED INDEX ixOrganisationMembers on OrganisationMembers(OrganisationId)
这将转换为以下实体RelationShip图: