用于存储图像的SQL Server表/索引

时间:2013-07-30 01:45:13

标签: sql-server image performance indexing

我在将数据库存储到数据库时遇到了一些问题。我们目前有大约40万条记录,但我预计这会很快增加到数百万条。目前我已经遇到了性能问题,所以这是一个主要问题。我在决定使用SQL Server存储图像之前做了一些研究,我读到的所有内容都表明它能够做到这一点。

我设计的表非常简单,包含3列......

  • Id(主键,唯一标识符,非空)
  • ImageHash(唯一标识符,非空)
  • BinaryImage(varbinary(max),not null)

逻辑是我在我的应用程序代码中生成ImageHash。图像哈希用于在插入之前进行查找,以查看数据库中是否已存在二进制图像。其余的时间我只是直接使用Id查询表。

我正在使用.NET Entity Framework来执行我的数据访问。 Id列是在插入时生成的,不确定这是否是最佳实践。

这是我的表的创建脚本。我为ImageHash创建了一个索引,但是我对SQL Server索引并不是很了解。

CREATE TABLE [dbo].[ImageContent](
    [Id] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [ImageHash] [uniqueidentifier] NOT NULL,
    [BinaryImage] [varbinary](max) NOT NULL,
 CONSTRAINT [PK_ImageData] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

ALTER TABLE [dbo].[ImageContent] ADD  CONSTRAINT [DF_ImageData_Id]  DEFAULT (newid()) FOR [Id]

和指数......

CREATE NONCLUSTERED INDEX [ImageHash_Index] ON [dbo].[ImageContent]
(
    [ImageHash] ASC
)
INCLUDE (   [Id]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

我重建了所有索引,但尚未解决问题。我一直在使用SQL Server Profiler,我发现导致问题的SQL插件(从实体框架生成)。这是二进制语句,但我已将其中的大部分截断为......这是在30秒后超时......

exec sp_executesql N'declare @generated_keys table([Id] uniqueidentifier)
insert [dbo].[ImageContent]([ImageHash], [BinaryImage])
output inserted.[Id] into @generated_keys
values (@0, @1)
select t.[Id]
from @generated_keys as g join [dbo].[ImageContent] as t on g.[Id] = t.[Id]
where @@ROWCOUNT > 0',N'@0 uniqueidentifier,@1 varbinary(max) ',@0='DF76D1FF-5C05-58E0-0933-1ADBCC6345A8',@1=0xFFD8FFE1214545786966000049492A00080000000D00000103...

所以我的问题是......

  • 任何人都可以通过我的设置方式看到一些重大问题吗?
  • 您是否有任何建议可以帮助我改善表现?
  • SQL Server能否以这种方式存储数百万张图像?

提前感谢您的时间!

2 个答案:

答案 0 :(得分:2)

因为您的索引(包括主键上的聚簇索引)位于uniqueidentifier上,所以这些索引将非常快速地分段。

  1. 考虑将单调增加的INT / BIGINT IDENTITY作为您的身份证明,除非您有充分的理由不这样做
  2. 调整NCI上的填充因子(ImageHash_Index)并确保您有一个工作来定期重新组织/重建
  3. 如果实际图像大于2 MB,请考虑使用FILESTREAM存储。这里有一份白皮书:http://msdn.microsoft.com/library/hh461480。如果你走这条路线,还有其他两个性能考虑因素。有关他们的信息:http://msdn.microsoft.com/en-us/library/ee377058(v=bts.10).aspx
  4.   

    禁用短文件名(8.3)生成   当长文件名是   使用Windows NTFS文件系统创建,默认行为是   在旧的8.3 DOS文件中生成相应的短文件名   与旧操作系统兼容的名称约定。这个   可以通过注册表项禁用功能,提供   性能提升。

    fsutil behavior set disable8dot3 1

      

    禁用NTFS上次访问更新   NTFS上的每个文件和文件夹   volume包含一个名为Last Access Time的属性。这个属性   显示上次访问文件或文件夹的时间,例如用户时   执行文件夹列表,将文件添加到文件夹,读取文件或   对文件进行更改。维护此信息会产生   文件系统的性能开销,尤其是在环境中   快速访问大量文件和目录的地方   在很短的时间内,例如使用BizTalk文件时   适配器。除了在高度安全的环境中,保留这一点   信息可能会增加服务器的负担,可以避免   更新以下注册表项:

    fsutil行为设置disablelastaccess 1

答案 1 :(得分:0)

你需要做尽职调查并收集至少一些最小的信息,因为这是任何人猜测问题是什么。您需要做的第一件事是阅读Waits and Queues以熟悉用于排除SQL Server性能问题的正确调查技术,并应用该方法来收集相关信息。

现在我的观点是基于没有任何证据的。您的INSERT可能会阻塞,我们无法知道原因。使用Activity Monitor了解阻止INSERT的内容。这不是由碎片造成的(永恒的red herring)。如果我冒昧地猜测,罪魁祸首是使用默认范围新的System.Transactions和awful serialization isolation this brings

作为旁注:UNIQUEIDENTIFIER是散列的可怕数据类型选择。要生成与图像有某种关联的哈希,您必须运行哈希算法,如MD5或SHA。您可能正在使用MD5并生成16字节密钥,但绝对没有理由将其存储为16字节长度UNIQEUIDENTIFIER类型。使用BINARY(16)。如果你想在将来转移到SHA1(20字节散列)或其他散列,也要考虑。