4

我有一个数据库,它被设置为对 varbinary(max) 字段上的音频文件使用 blob FileStream。它的大小已经增长到 80GB 以上,我正面临性能问题。

环顾四周后,我发现我的平均 blob 大小约为 180k。由于根据MSDN文件流应该用于超过 1MB 的对象,我正在重新评估如何存储这些 blob。MSDN 还指出,“对于较小的对象,将 varbinary(max) BLOB 存储在数据库中通常会提供更好的流式传输性能。” 所以我正在考虑从带有文件流的 varbinary(max) 转移到只使用 varbinary(max) 字段。

所以我的问题是,有没有一种很好的方法使用 sql 脚本将每个文件流 blob 从文件流移动到实际的 varbinary 字段本身?在决定询问之前我一直在研究的替代方法是让 ac# app 查询数据库中的 blob 并将每个 blob 写入文件系统。然后手动从数据库中删除文件流内容。然后让 c# 应用程序从文件系统读取 blob 并写回数据库。我想必须有一个更简单的方法。

4

1 回答 1

7

假设您的源表如下所示:

CREATE TABLE audioFiles
(
    AudioID INT IDENTITY NOT NULL PRIMARY KEY,
    [Name] VARCHAR(50) NOT NULL,
    [AudioData] VARBINARY(MAX) FILESTREAM NULL,
    RowGuid UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL UNIQUE DEFAULT(NEWID())
)

然后你可以创建第二个表:

CREATE TABLE audioBlobs
(
    AudioID INT IDENTITY NOT NULL PRIMARY KEY,
    [Name] VARCHAR(50) NOT NULL,
    [AudioData] VARBINARY(MAX) NULL,
    RowGuid UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL UNIQUE DEFAULT(NEWID())
)
GO

(请注意,AudioData第二个表中的列中缺少 FILESTREAM ......导致二进制数据与记录的其余部分一起存储在页面上,而不是在单独的 FILESTREAM 文件组中。)

然后您可以将数据从一个表插入到另一个表中:

SET IDENTITY_INSERT audioBlobs ON

INSERT INTO audioBlobs (AudioID, Name, AudioData, RowGuid)
    SELECT AudioID, Name, AudioData, RowGuid FROM audioFiles

SET IDENTITY_INSERT audioBlobs OFF

完成后,您可以删除原始表,并将新表重命名为原始表的名称:

DROP TABLE audioFiles
GO

EXECUTE sp_rename N'dbo.audioBlobs', N'audioFiles', 'OBJECT' 
GO

VARBINARY(MAX)或者,您可以在原始表中的列旁边创建第二列FILESTREAM,并使用旧列的数据更新新列的值。请注意,无论采用哪种方式,您的总磁盘空间使用量都会增加一倍以上——实际音频数据的空间增加一倍,将其从 FILESTREAM 文件组迁移到 PRIMARY 文件组(或主数据文件所在的任何位置),再加上您的事务日志中有很多空间。

于 2012-08-31T16:41:46.403 回答