在数据库中存储不同图像的最佳方法是什么?

Pat*_*ick 10 sql database sql-server database-design

为不同目的存储图像的最佳方法(关于数据库设计)是什么?

我有一堆用户照片,我有另外5套不同的照片(如用户照片,但没有连接到用户照片).

将所有照片存储在单个数据库表中并尝试从该表中引用它们是最好的,还是最好为每组照片创建不同的表?

我可以看到创建多个表的一个好处,那就是删除主对象时删除照片的级联删除功能.

还需要考虑其他方面吗?

另一个例子可能是地址.用户可以拥有地址,但公司或位置也可以.为所有地址创建一个表,并尝试使用某种索引表来引用哪个地址属于哪个对象或具有不同的表并消除问题.

Fil*_*Vos 14

如何在sql server中存储大blob

在SQL Server中存储大量二进制数据并不是一个好方法.它使您的数据库非常庞大,备份和性能通常不是很好.存储文件通常在文件系统上完成.Sql Server 2008具有开箱即用的支持FILESTREAM.Microsoft将案例记录为使用FileStream,如下所示

  • 存储的对象平均大于1 MB.
  • 快速读取访问很重要.
  • 您正在开发使用中间层进行应用程序逻辑的应用程序.

在你的情况下,我认为所有要点都是有效的.

在服务器上启用

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插入数据

现在要在此表中插入数据,您可以使用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)

如何建模Photo存储数据库

使用文件流方法来存储图像时,表格非常窄,这有利于提高性能,因为每个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)

这转换为以下实体关系图:

实体关系图

  • 性能方面,窄图像表非常好,因为它每个记录只包含几个字节的数据.
  • 我们可以假设图像始终是图像集的成员,如果图像集中只有1个图像,则可以隐藏集合信息.
  • 我假设你想跟踪哪些用户是哪个组织的成员,所以我添加了一个表来链接它们(假设用户可以是多个组织的成员).
  • OrganisationMembers表上的主键具有UserId作为第一个字段,因为通常比组织更多的用户,并且您可能希望显示用户成员的组织比反向更多.
  • OrganisationMembers中的OrganisationId索引用于满足需要显示特定组织的成员列表的查询.

参考文献: