FILESTREAM (SQL Server)

FILESTREAM 使基于 SQL Server 的应用程序能够将非结构化数据(如文档和图像)存储在文件系统上。 应用程序可以利用文件系统的丰富流式处理 API 和性能,同时保持非结构化数据和相应结构化数据之间的事务一致性。

FILESTREAM 通过将 varbinary(max) 二进制大型对象(BLOB)数据存储为文件系统上的文件,将 SQL Server 数据库引擎与 NTFS 文件系统集成。 Transact-SQL 语句可以插入、更新、查询、搜索和备份 FILESTREAM 数据。 Win32 文件系统接口提供对数据的流访问。

FILESTREAM 使用 NT 系统缓存来缓存文件数据。 这有助于降低 FILESTREAM 数据可能对数据库引擎性能产生的任何影响。 不使用 SQL Server 缓冲池;因此,此内存可用于查询处理。

安装或升级 SQL Server 时,不会自动启用 FILESTREAM。 必须使用 SQL Server Configuration Manager 和 SQL Server Management Studio 启用 FILESTREAM。 若要使用 FILESTREAM,必须创建或修改数据库以包含特殊类型的文件组。 然后,创建或修改表,使其包含 varbinary(max) 具有 FILESTREAM 属性的列。 完成这些任务后,可以使用 Transact-SQL 和 Win32 来管理 FILESTREAM 数据。

有关安装和使用 FILESTREAM 的详细信息,请参阅 相关任务的列表。

何时使用 FILESTREAM

在 SQL Server 中,BLOB 可以是将数据存储在表中的标准 varbinary(max) 数据,也可以是存储在文件系统中的 FILESTREAM varbinary(max) 对象。 数据的大小和使用决定了是应使用数据库存储还是文件系统存储。 如果满足以下条件,应考虑使用 FILESTREAM:

  • 正在存储的对象平均大于 1 MB。

  • 快速读取访问非常重要。

  • 你正在开发使用中间层进行应用程序逻辑的应用程序。

对于较小的对象,将 varbinary(max) BLOB 存储在数据库中通常可提供更好的流式处理性能。

FILESTREAM 存储

FILESTREAM 存储以 varbinary(max) 列的形式实现,其中数据作为 BLOB 存储在文件系统中。 BLOB 的尺寸仅受文件系统卷容量的限制。 2 GB 文件大小的标准 varbinary(max) 限制不适用于存储在文件系统中的 BLOB。

若要指定列应在文件系统上存储数据,请在列上 varbinary(max) 指定 FILESTREAM 属性。 这会导致数据库引擎在文件系统上存储该列的所有数据,但不存储在数据库文件中。

FILESTREAM 数据必须存储在 FILESTREAM 文件组中。 FILESTREAM 文件组是一个特殊文件组,其中包含文件系统目录,而不是文件本身。 这些文件系统目录称为 数据容器。 数据容器是数据库引擎存储和文件系统存储之间的接口。

使用 FILESTREAM 存储时,请考虑以下事项:

  • 当表包含 FILESTREAM 列时,每行必须具有非空唯一行 ID。

  • 可将多个数据容器添加到 FILESTREAM 文件组。

  • 无法嵌套 FILESTREAM 数据容器。

  • 使用故障转移群集时,FILESTREAM 文件组必须位于共享磁盘资源上。

  • FILESTREAM 文件组可以位于压缩卷上。

集成管理

由于 FILESTREAM 作为列 varbinary(max) 实现并直接集成到数据库引擎中,因此大多数 SQL Server 管理工具和函数无需修改 FILESTREAM 数据即可工作。 例如,可以将所有备份和恢复模型用于 FILESTREAM 数据,并且 FILESTREAM 数据使用数据库中的结构化数据进行备份。 如果不想使用关系数据备份 FILESTREAM 数据,可以使用部分备份来排除 FILESTREAM 文件组。

集成安全性

在 SQL Server 中,FILESTREAM 数据与其他数据一样受到保护:通过向表或列级别授予权限。 如果用户有权访问表中的 FILESTREAM 列,则用户可以打开关联的文件。

注释

FILESTREAM 数据不支持加密。

仅向运行 SQL Server 服务帐户的帐户授予对 FILESTREAM 容器的 NTFS 权限。 建议不向其他帐户授予对数据容器的权限。

注释

SQL 登录无法与 FILESTREAM 容器配合使用。 只有 NTFS 身份验证才能与 FILESTREAM 容器一起工作。

使用 Transact-SQL 和文件系统流访问 BLOB 数据

将数据存储在 FILESTREAM 列中后,可以使用 Transact-SQL 事务或使用 Win32 API 访问文件。

Transact-SQL Access

通过使用 Transact-SQL,可以插入、更新和删除 FILESTREAM 数据:

  • 可以使用插入操作来预填充 FILESTREAM 字段,使其具有 NULL 值、空值或相对较短的内联数据。 但是,大量数据更有效地流式传输到使用 Win32 接口的文件。

  • 更新 FILESTREAM 字段时,即会修改文件系统中的基础 BLOB 数据。 将 FILESTREAM 字段设置为 NULL 即会删除与该字段相关联的 BLOB 数据。 您不能使用 Transact-SQL 分块更新,该分块更新通过 UPDATE**.**Write() 方法进行实现,从而对数据进行部分更新。

  • 当您删除某行或删除或截断包含 FILESTREAM 数据的表时,将删除文件系统中的基础 BLOB 数据。

文件系统数据流访问

Win32 流式处理支持在 SQL Server 事务的上下文中工作。 在事务中,可以使用 FILESTREAM 函数获取文件的逻辑 UNC 文件系统路径。 然后使用 OpenSqlFilestream API 获取文件句柄。 然后,Win32 文件流式处理接口(如 ReadFile()和 WriteFile()可以使用此句柄通过文件系统访问和更新文件。

由于文件作是事务性的,因此无法通过文件系统删除或重命名 FILESTREAM 文件。

语句模型

FILESTREAM 文件系统使用打开和关闭文件为 Transact-SQL 语句建模。 该语句在打开文件句柄时开始,并在句柄关闭时结束。 例如,当写入句柄关闭时,在表上注册的任何可能 AFTER 触发器就会触发,就好像 UPDATE 语句已完成一样。

存储命名空间

在 FILESTREAM 中,数据库引擎控制 BLOB 物理文件系统命名空间。 新的内部函数 PathName 提供 BLOB 的逻辑 UNC 路径,该路径对应于表中每个 FILESTREAM 单元格。 应用程序使用此逻辑路径来获取 Win32 句柄,并使用常规 Win32 文件系统接口对 BLOB 数据进行作。 如果 FILESTREAM 列的值为 NULL,则该函数将返回 NULL。

事务处理文件系统访问

新的内部函数 GET_FILESTREAM_TRANSACTION_CONTEXT()提供表示会话关联的当前事务的令牌。 事务必须已启动,但尚未中止或提交。 通过获取令牌,应用程序将 FILESTREAM 文件系统流式处理作与启动的事务绑定。 如果未显式启动事务,该函数将返回 NULL。

在事务提交或中止之前,必须关闭所有文件句柄。 如果句柄在事务范围之外保持打开状态,则针对句柄的其他读取将导致失败;针对句柄的其他写入将成功,但实际数据不会写入磁盘。 同样,如果数据库引擎的数据库或实例关闭,则所有打开的句柄都会失效。

事务持续性

通过 FILESTREAM,在提交事务后,数据库引擎可确保从文件系统流访问修改的 FILESTREAM BLOB 数据的事务持久性。

隔离语义

隔离语义由数据库引擎事务隔离级别控制。 Transact-SQL 和文件系统访问支持读取提交的隔离级别。 支持可重复读取操作、可序列化和快照隔离。 不支持脏读。

文件系统访问打开操作不会等待任何锁。 相反,如果由于事务隔离而无法访问数据,打开的操作会立即失败。 如果由于隔离冲突而无法继续打开操作,则流式处理 API 调用会失败并出现 ERROR_SHARING_VIOLATION。

为了允许进行部分更新,应用程序可以发出设备 FS 控制命令(FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT),以将旧内容提取到打开的句柄所引用的文件中。 这将触发服务器端旧内容复制。 为了提高应用程序的性能,并避免在处理非常大的文件时遇到潜在的超时问题,我们建议使用异步输入/输出操作。

如果在句柄被写入后发出 FSCTL,则最后一次写入将保留,并且对句柄进行的先前写入将丢失。

文件系统 API 和支持的隔离级别

当文件系统 API 由于隔离冲突而无法打开文件时,将返回ERROR_SHARING_VIOLATION异常。 当两个事务尝试访问同一文件时,会发生这种隔离违规。 访问作的结果取决于打开文件的模式以及运行事务的 SQL Server 版本。 下表概述了访问同一文件的两个事务的可能结果。

交易 1 交易 2 SQL Server 2008 的结果 SQL Server 2008 R2 及更高版本的结果
打开以供阅读。 打开以供阅读。 两者都成功了。 两者都成功了。
打开以供阅读。 打开进行写入。 两者都成功了。 事务 2 下的写入操作不会影响在事务 1 中执行的读取操作。 两者都成功了。 事务 2 中的写入操作不会影响在事务 1 中进行的读取操作。
打开进行写入。 打开以供阅读。 打开事务 2 失败,并出现 ERROR_SHARING_VIOLATION 异常。 两者都成功了。
打开以写入 打开进行写入。 事务 2 的打开失败,并出现ERROR_SHARING_VIOLATION异常。 打开事务 2 时失败,出现ERROR_SHARING_VIOLATION异常。
打开以供阅读。 打开 SELECT。 两者都成功了。 两者都成功了。
打开以供阅读。 打开以进行更新或删除。 两者都成功了。 事务 2 下的写入作不会影响在事务 1 中执行的读取作。 两者都成功了。 事务 2 中的写入操作不会影响在事务 1 中执行的读取操作。
打开以进行写入。 打开 SELECT。 事务 2 会等待事务 1 提交或结束事务,或者事务锁定超时。 两者都成功了。
打开以写入 开放执行 UPDATE 或 DELETE。 事务 2 会被阻塞,直到事务 1 提交、结束事务,或者事务锁定超时。 事务 2 会阻塞,直到事务 1 提交、结束或事务锁定超时。
打开SELECT功能。 打开以供阅读。 两者都成功了。 两者都成功了。
打开 SELECT。 打开进行写入。 两者都成功了。 事务 2 下的写操作不会影响事务 1。 两者都成功了。 事务 2 下的写操作不会影响事务 1。
可用于更新或删除。 打开以供阅读。 事务 2 的打开操作失败,并出现一个ERROR_SHARING_VIOLATION异常。 两者都成功了。
开启更新或删除操作 打开以进行写入。 事务 2 上的打开操作失败,并出现ERROR_SHARING_VIOLATION异常。 事务 2 的打开操作因出现 ERROR_SHARING_VIOLATION 异常而失败。
启用可重复读取的 SELECT。 打开以供阅读。 两者都成功了。 两者都成功了。
打开具有可重复读取的 SELECT。 打开进行写入。 事务 2 上的打开操作失败,并出现ERROR_SHARING_VIOLATION异常。 事务 2 上的打开作失败,并出现ERROR_SHARING_VIOLATION异常。

从远程客户端Write-Through

通过服务器消息块 (SMB) 协议启用了对 FILESTREAM 数据的远程文件系统访问。 如果客户端是远程的,则写操作不会在客户端被缓存。 写入操作将始终被发送到服务器。 可以在服务器端缓存数据。 建议在远程客户端上运行的应用程序将小型写入操作合并,以较大的数据量减少写入操作次数。

不支持使用 FILESTREAM 句柄创建内存映射视图(内存映射 I/O)。 如果将内存映射用于 FILESTREAM 数据,则数据库引擎无法保证数据的一致性和持久性或数据库的完整性。

相关任务

启用和配置 FILESTREAM
创建 FILESTREAM-Enabled 数据库
创建用于存储 FILESTREAM 数据的表
使用 Transact-SQL 访问 FILESTREAM 数据
为 FILESTREAM 数据创建客户端应用程序
使用 OpenSqlFilestream 访问 FILESTREAM 数据
对 FILESTREAM 数据进行部分更新
避免与 FILESTREAM 应用程序中的数据库操作发生冲突
移动 FILESTREAM-Enabled 数据库
在故障转移群集上设置 FILESTREAM
为 FILESTREAM 访问配置防火墙

相关内容

FILESTREAM 与其他 SQL Server 功能的兼容性