【问题标题】:What is the benefit of having varbinary field in a separate 1-1 table?在单独的 1-1 表中包含 varbinary 字段有什么好处?
【发布时间】:2010-12-01 10:50:27
【问题描述】:

我需要将二进制文件存储在 SQL Server 2005 上的 varbinary(max) 列中,如下所示:

文件信息

  • FileInfoId int、PK、身份
  • FileText varchar(max)(可以为空)
  • FileCreatedDate 日期时间等

文件内容

  • FileInfoId int、PK、FK
  • FileContent varbinary(max)

FileInfo 与 FileContent 具有一对一的关系。 FileText 用于在没有文件要上传的情况下使用,并且仅为项目手动输入文本。我不确定有多少百分比的项目会有二进制文件。

我应该创建第二个表吗?两个表的设计会有任何性能改进吗?有什么合乎逻辑的好处吗?

我找到了this page,但不确定它是否适用于我的情况。

【问题讨论】:

    标签: sql-server sql-server-2005 performance database-design varbinary


    【解决方案1】:

    没有性能或运营优势。从 SQL 2005 开始,引擎已经将 LOB 类型存储在单独的分配单元(单独的 b 树)中。如果您研究 SQL Server 的Table and Index Organization,您会发现每个分区最多有 3 个分配单元:数据、LOB 和行溢出:


    (来源:s-msft.com

    LOB 字段(varchar(max)、nvarchar(max)、varbinary(max)、XML、CLR UDT 以及不推荐使用的类型 text、ntext 和 image)将在聚集索引中的数据记录本身中具有,仅占用很小的空间:指向 LOB 分配单元的指针,请参阅Anatomy of a Record

    通过将 LOB 显式存储在单独的表中您将一无所获。您只是增加了不必要的复杂性,因为以前的原子更新现在必须将自己分布到两个单独的表中,从而使应用程序和应用程序事务结构复杂化。

    如果 LOB 内容是整个文件,那么也许您应该考虑升级到 SQL 2008 并使用FILESTREAM

    【讨论】:

    • 谢谢!这正是我正在寻找的信息。现在很清楚了。但我想知道...也许 1-1 分离方法可以追溯到 SQL Server 2000 时代,当时 varbinary(max) 还没有以 SQL Server 2005 中的形式存在,并且使用了 text、ntext 和 image用于存储二进制文件?为什么别人会有这种想法?还是真的只是防止人们犯SELECT *错误的一个原则?但他们仍然可以使用连接:)
    • +1 Remus,我忘了这个 2005 年及更高版本的功能。关于 2008 年的 FILESTREAM,我不会急于将它用于任何规模可观的存储库。以必须维护与普通文件系统存储库相关的“标头数据”的引用完整性为代价,这种方法在扩展、备份、镜像、TCO 方面确实提供了一些操作优势......跨度>
    • @mjv:如果必须从 Win32 API 访问文件(例如 SharePoint 等文档集成),则 FILESTREAM 具有一些优势。备份/恢复包含文件流内容,但它确实不适用于镜像。与任何新功能一样,如何扩展它的技巧需要一段时间才能渗透到常识中,但我知道它可以扩展。在 TCO 上,我确信我了解您所指的成本。部署设置成本和培训?
    • @Dragoljub:坦率地说,我不确定关于 LOB 分离的建议是如何开始的。在 2005 年之前,text/ntext/image 字段仍然存储在表之外(一团乱七八糟的毛球存储,但不是集群叶页的一部分,因此不属于扫描/搜索)。我只能认为 DBA 试图避免 * 在投影列表中的影响。
    • 您的 GIF 图片链接看起来已失效。
    【解决方案2】:

    这种两表设计并没有真正的逻辑优势,因为关系是 1-1,您可能会将所有信息捆绑在 FileInfo 表中。但是,它有很大的操作和性能优势,尤其是当您的二进制数据的大小平均超过几百字节时。

    编辑:正如 Remus Rusanu 所指出的,在 SQL2005 等一些 DBMS 实现中,大对象类型被透明地存储到单独的表中,有效地缓解了拥有大记录的实际缺陷。这个特性的引入隐含地证实了 [true] 单表方法的弱点。

    我只是扫描了这个问题中引用的 SO 帖子。我通常认为,虽然其他帖子提出了一些有效的观点,例如内在数据完整性(因为对给定项目的所有 CRUD 操作都是原子的),但总的来说,除非是相对非典型的用例(例如使用该项目表作为存储库,一次主要查询单个项目),性能优势在于两个表方法(“标题”表上的索引将更有效,不需要二进制数据的查询将更快地返回等. 等等)

    如果设计演变为在不同的上下文中提供不同类型的二进制对象,则两个表方法具有进一步的好处。例如,假设这些项目是图像(GIF、JPG 等)。以后您还想提供这些图像的小型预览版本(和/或高分辨率版本),其选择由上下文(用户偏好、低带宽客户端、订阅者与访问者)驱动等等。)。在这种情况下,不仅与单表方法相关的操作问题变得更加尖锐,而且模型变得更加通用。

    【讨论】:

    • 如果您倾向于习惯性地使用 SELECT * 而不是 SELECT 只使用您需要的列,我只能看到问题。
    • 这本身就是不好的做法。解决方法是停止使用 SELECT *,而不是更改数据库设计。
    • 有人会说单表设计是好的,因为与 [不必要] SELECT * 相关的慢查询最终会迫使开发人员避免使用 * 做法。 :-) 然而,我认为我支持两表方法的观点独立于 SELECT * 实践。
    • 我同意 SELECT *,但我从不使用它。我想我的目标与索引和其他列的读取完全相关,如果我们将 varbinary 列放在单独的表中,那会消耗更少的 CPU 和内存吗?假设我没有在 select 语句中包含 varbinary 列。
    • Tablescans 必须扫描 lob 描述符,这可能影响较小,因为索引扫描问题较小(仅使用较少的缓存空间)
    【解决方案3】:

    这有助于将 IMAGE、(N)TEXT、(N)VARCHAR(max) 和 VARBINARY(max) 列从更宽的表中分离出来,这纯粹是为了 SQL Server 的一些限制。

    例如,在 2012 年之前,如果聚簇表包含 LOB,则无法在线重建聚簇表。另一方面,您可能不关心这些限制,因此最好将表设置为与您的数据相关。

    如果您实际上希望将 LOB 数据保留在表分配单元之外,您仍然可以设置“行外大值类型”table option

    【讨论】:

      猜你喜欢
      • 2014-10-09
      • 1970-01-01
      • 1970-01-01
      • 2014-02-14
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-15
      相关资源
      最近更新 更多