Dan*_*aar 6 sql-server sql-server-2012 filestream
我们有一个FILESTREAM
包含几百万个文件的容器,我们相信这是我们遇到的性能问题(大量超时)的原因。
根据这个关于FILESTREAM
最佳实践的博客,每个容器不应超过 300,000 个文件。
根据此处接受的答案,除非将表重新创建到新FILESTREAM
位置,否则无法完成它。
表的结构如下:
CREATE TABLE [dbo].[Documents](
[ContentPath] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[FileContent] [varbinary](max) FILESTREAM NULL,
CONSTRAINT [UQ_IX_Documents_ContentPath] UNIQUE NONCLUSTERED
(
[ContentPath] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY] FILESTREAM_ON [FSFileGroup_1]
Run Code Online (Sandbox Code Playgroud)
我们使用的是 SQL Server 2012。不幸的是,不是 Enterprise(我们最近才意识到它支持每个文件组多个容器)。
尽管我们从不进行记录更新,但我们进行了大量写入,可能与读取一样多。模式是:一次一个,由 ContentPath 读取,并且没有特定的容器或顺序写入。
我想,对您来说,一个不错的选择是在逻辑上拆分表,因此每个部分都将位于自己的文件夹中,并且文件数低于 300k(=记录)。
在 SQL Server 中,逻辑表拆分通常是通过分区完成的(这是一项企业功能)。分区本质上将表的部分(分区)映射到物理存储(文件组)。不同的分区可以分配给不同的文件组。FILESTREAM
本质上是文件组的一个属性。
这构成了您的解决方案的主干:
以下是如何使用FILESTREAM
column对表进行分区。
主要优势: 您将能够一次管理FILESTREAM
每个分区的数据,而不是整个表。
你需要:
允许跟踪分区大小或至少不允许跨分区随机写入的 ID
[Id] [uniqueidentifier] ROWGUIDCOL NOT NULL DEFAULT (newsequentialid())
Run Code Online (Sandbox Code Playgroud)维护工作,检查最后一个分区的完整程度,提前创建新的文件组和分区,重建每个分区的索引等。
为了满足Insert
操作让你的分区小于300k,所以索引一次重建一个分区。
这种设计主要用于只读表,在它的末尾进行插入。如果您还没有这样做,请务必考虑写入和更新以及分区对它们的影响。
为了对表进行分区,您需要建立一个索引。主要有2种方式:
重建整个表的索引。它将需要比表多 x2-x3 倍的空间。由于多种原因,它不适合大桌子。
将数据迁移到已经分区的新表中。
我对此的首选方法:
DELETE... OUTPUT DELETED ... INTO <intermediary table>
用于适合 1 个分区的数据。理想情况下,新插入的行应该进入最后一个分区。但是,有一个关于NEWSEQUENTIOALID()
函数的问题:
创建一个 GUID,该 GUID 大于自 Windows 启动以来此函数在指定计算机上先前生成的任何 GUID。重新启动 Windows 后,GUID 可以从较低的范围再次启动,但仍然是全局唯一的。
这意味着新的写入只会进入最后一个分区,直到第一次重新启动服务器。而这最终会发生。新行将插入表格中间。但还记得我们现在有分区吗?一次只有一个分区会受到影响。它仍然会在某个时间点超过 30 万行。
这里的主要选项是拆分分区。现有分区将一分为二,其中右侧部分将形成一个新分区。新分区应该进入新文件组。这将不仅仅是元数据操作:文件将被物理复制到另一个分区。
解决方法是在同一个 PS 上移动(删除行并将行插入中间表)行;拆分分区并将行移回。但无论如何它都涉及一次移动数据。如果中间表在同一个 PS 上,那么拆分将涉及移动数据。如果没有,则需要第二次将数据移回主表。
多个 FILESTRAM 容器是企业版的一个特性。容器通常被称为容器中的“文件夹” FILESTREAM
。实际上它是FILESTREAM
类型文件组中的数据库文件。
将每个 NTFS 文件夹中的文件数控制在 300k 以下确实有帮助,但要明确管理这些文件夹中存储的文件是非常困难的。
文章重新平衡跨文件中的数据文件组由保罗·兰德尔从2011年给出了使用文件组文件的提示:
[SQL Server] 还使用一种称为比例填充的算法,该算法旨在根据文件相对于文件组中其他文件的可用空间量从文件中分配数据。
...
这意味着,如果您将新数据文件添加到主要包含完整数据文件的文件组中,则比例填充权重将使得新文件将成为分配来源的文件,直到它填充到与旧文件相同的级别文件。新文件实质上成为一个分配热点。
SQL Server 将首先填充新添加的文件,直到它们填充到与其他文件相同的 %age 级别。
它可能看起来是分区的一种更简单的替代方法,但事实并非如此:
同时,您可以将多个 FILESTREAM 容器混合到分区解决方案中,使文件夹更小、更快。
SE 没有分区或多FILESTREAM
容器。这意味着我们每个表只能有一个分区和一个容器。
一种选择是拥有多个UNION ALL
顶部有视图的表。
UNION ALL
所有表的视图。提示:为了避免扫描所有表,WHERE
为属于该特定表的 ID添加一个子句。它将帮助优化器排除特定不存在的表: Select * from Table1 where ID between 1 and 100
UNION ALL
Select * from Table2 where ID between 101 and 10000
UNION ALL
Select * from Table3 where ID between 10001 and 100000000
Run Code Online (Sandbox Code Playgroud)
请确保您从覆盖GUID的所有可能的值0000-...-0000
来FFFF-...-FFFF
-这种观点将可更新的,所以你就可以使用此视图将数据插入相关表格。有一些模仿:通过视图修改数据。- 您需要将所有数据从现有表物理复制到新表。它可以通过主视图来实现。
PS SQL Server 首先是一个 RDMS。管理大量非结构化数据的功能,如VARBINARY(MAX)
附加组件和相对较新的。因此,还需要考虑其他限制:
每个表的最大分区数:15 000 最大文件组或每个数据库的文件:32 767 每个容器的最大文件:300 000(在我的示例中=文件组,=每个文件组有多个容器的情况下的数据库文件)
事务日志的大小是对一个事务以及完成事务所需时间的限制。您需要保持单个操作的可管理性,并且可以在合理的时间内回滚。
归档时间: |
|
查看次数: |
3225 次 |
最近记录: |