小编典典

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

sql

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

我有一堆用户照片,另外还有五套不同的照片(例如用户照片,但与用户照片没有关联)。

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

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

还有其他方面需要考虑吗?

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


阅读 206

收藏
2021-04-15

共1个答案

小编典典

注意:现在ancient,此答案是正确的,我建议您将图像上传到Amazon S3,Google Cloud Storage或Azure
Blob存储帐户,并将ID存储在数据库中。将How to model a Photo storage database仍然是相关的。

如何在SQL Server中存储大Blob

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

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

以您的情况,我认为所有观点都是有效的。

在服务器上启用

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属性,还需要具有该属性的字段。

使用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();
}

使用插入数据 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();
            }
        }

如何为照片存储数据库建模

使用文件流方法来存储图像时,表非常狭窄,这对性能很有好处,因为每个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图:

  • 在性能方面,窄图像表非常好,因为每个记录仅包含几个字节的数据。
  • 我们可以假设图像始终是图像集的成员,如果其中仅包含1张图像,则该集信息可能会被隐藏。
  • 我假设您想跟踪哪些用户是哪个组织的成员,所以我添加了一个表来链接它们(假设一个用户可以是多个组织的成员)。
  • OrganisationMembers表上的主键将UserId作为第一个字段,因为通常用户数比Organizations多,并且您可能想显示某个用户所属的组织比倒数更多。
  • OrganisationMembers中OrganisationId上的索引可满足需要显示特定组织的成员列表的查询。
2021-04-15