免责声明
不久前我有一个桌子设计的想法,当时对我来说很有意义。在最近的历史中,我意识到我有“过度设计”或花费太多时间试图“过度优化”解决方案的习惯。我假设这是我过度思考解决方案并且会产生额外开销而几乎没有实际收益的情况之一。
问题
假设一个对象(Shipment
table
例如 a)有某种NOTE
varchar(MAX)
我们想要跟踪的数据元素。NOTE
column
有机会将数据推入溢出并显着增加大小(row
从而限制rows
可以保存在 上的数量page
)。据我了解,这会对整个表上各种操作的执行时间产生负面影响。
有没有一个例子,我们应该把它推column
到一个单独的独立设备上,ShipmentNote
table
而不是把它column
放在Shipment
table
. 理论是,如果我们将其推NOTE
column
入一个单独table
的位置,它会保存pages
on,Shipment
table
这使得所有操作都Shipment
table
可以更好地执行。因为row
尺寸更小,现在您可以rows
在相同的尺寸上安装更多page
。
(请参见下面的架构示例):
这可能是一个好主意的主要用例是:
Note
column
通常超过 8000 个字符(我认为这是我们开始使用额外分页的时候)- 操作中
Note
column
唯一返回的,SELECT
很少或从不用作JOIN
or的一部分WHERE
- 其余
columns
的Shipment
将被Note
定期独立查询(即:我们的大部分操作,不会使用Note
,JOIN
或者WHERE
其他发生columns
在“装运”中的情况)
我看到的缺点(除此之外,在使用列Shipment
外的表格时可能实际上并没有明显的改进Note
):
- 现在变得不可能(或至少需要 a
trigger
或其他东西)确保总是有某种价值NOTE
(即:因为它现在是单独的child table
,我们无法确保它NOTE
适用于NOT NULL
每个row
Shipment
- 现在使用任何操作
NOTE
都需要额外的努力,因为需要做一个JOIN
以确保我们正在使用正确的记录
尽管您甚至在考虑这一点都很棒-我认为这是微优化。SQL Server 已经内置了用于处理的优化
NVARCHAR(MAX)
,所以通常我会说不要再猜测它,直到它成为一个问题。但是,在阅读您的问题时,我想到了两个要点。第一个是(正如您在最后一点提到的那样)实际上是否会通过将数据拆分到另一个表中而不是让 SQL Server 优化页面和数据本身来获得任何性能?我现在没有确凿的证据,但我怀疑没有。原因是,正如您所提到的,您的数据通常超过 8000 字节,因此无论如何都会移动到 Note 表中的 LOB 页面。您只是将感知到的问题从一张桌子转移到另一张桌子。加上必须获取数据时执行的开销,
JOIN
您最终可能会比开始时的情况稍差。其次,当您使用数据库设计标记问题时,我的实际建议是将注释拆分到另一个表中。但是,我的推理不是由性能优化驱动,而是更具体地说是为应用程序增加了灵活性。一件货物很可能需要附上一张以上的票据(例如,如果它在运输途中延误,或者客户来电等......)。如果您有关于实际货物本身的注释,则在不复制数据的情况下很难做到这一点。如果您将其提取到自己的表格中,您将能够为一个货件分配多个注释,并跟踪谁输入它们以及何时输入它们。这使您的应用程序和数据库更加灵活。
如果您想优化,那么我建议您无需查询注释,除非有人特别想查看它们(例如在您的应用程序中有一个专用表单来执行此操作)。这样,您只需要在有人明确想要查看数据时执行连接/查找。即使您没有将注释外部化到另一个表,如果不需要在查询中不包括该列,SQL Server 也无需读取 LOB 页面。如果可能的话,我总是会优化查询以在微观层面进行优化之前返回所需的最少信息量。
简单的答案是否定的,除非您有一个始终获取表的所有列的应用程序,并且您需要防止它在每次查询 Shipment 时检索注释。
如果您决定,您可以指示 SQL Server 永远不要将注释存储在行上,并使用指向带有表选项'large value types out of row'的单独 LOB 的指针,甚至可以通过以下方式将这些 LOB 推送到单独的文件组在CREATE TABLE中设置 TEXTIMAGE_ON 选项。