Pat*_*ick 10 sql database sql-server database-design
为不同目的存储图像的最佳方法(关于数据库设计)是什么?
我有一堆用户照片,我有另外5套不同的照片(如用户照片,但没有连接到用户照片).
将所有照片存储在单个数据库表中并尝试从该表中引用它们是最好的,还是最好为每组照片创建不同的表?
我可以看到创建多个表的一个好处,那就是删除主对象时删除照片的级联删除功能.
还需要考虑其他方面吗?
另一个例子可能是地址.用户可以拥有地址,但公司或位置也可以.为所有地址创建一个表,并尝试使用某种索引表来引用哪个地址属于哪个对象或具有不同的表并消除问题.
Fil*_*Vos 14
在SQL Server中存储大量二进制数据并不是一个好方法.它使您的数据库非常庞大,备份和性能通常不是很好.存储文件通常在文件系统上完成.Sql Server 2008具有开箱即用的支持FILESTREAM.Microsoft将案例记录为使用FileStream,如下所示
在你的情况下,我认为所有要点都是有效的.
要FILESTREAM在服务器上启用支持,请使用以下语句.
EXEC sp_configure filestream_access_level, 2
RECONFIGURE
Run Code Online (Sandbox Code Playgroud)
要获取链接到数据库的文件流文件组,请创建
ALTER DATABASE ImageDB ADD FILEGROUP ImageGroup CONTAINS FILESTREAM
ALTER DATABASE ImageDB
ADD FILE ( NAME = 'ImageStream', FILENAME = 'C:\Data\Images\ImageStream.ndf')
TO FILEGROUP TodaysPhotoShoot
Run Code Online (Sandbox Code Playgroud)
下一步是使用文件流存储将数据存储到数据库中:
CREATE TABLE Images
(
[Id] [uniqueidentifier] ROWGUIDCOL NOT NULL PRIMARY KEY,
[CreationDate] DATETIME NOT NULL,
[ImageFile] VARBINARY(MAX) FILESTREAM NULL
)
Run Code Online (Sandbox Code Playgroud)
为了Filestream工作,您不仅需要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();
}
Run Code Online (Sandbox Code Playgroud)
SqlFileStream还存在一种使用Win32直接在磁盘上获取文件数据的方法.这为您提供SqlFileStream继承的流媒体访问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();
}
}
Run Code Online (Sandbox Code Playgroud)
使用文件流方法来存储图像时,表格非常窄,这有利于提高性能,因为每个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)
Run Code Online (Sandbox Code Playgroud)
这转换为以下实体关系图:

参考文献: