当 nvarchar(4000) 99% 的时间都足够时,存储大数据的最佳做法是什么?

bri*_*ian 6 sql-server-2005 sql-server

我有一个大约 100MM 行的表,用于存储有关用户的信息。

CREATE TABLE [dbo].[UserData](
        [UserDataID] [int] IDENTITY(1,1) NOT NULL,
        [UserID] [int] NOT NULL,
        [DataId] int NOT NULL,
        [DataValue] [nvarchar](4000) NOT NULL,
        [EncryptedDataValue] [varbinary](max) NULL)
Run Code Online (Sandbox Code Playgroud)

我需要能够将数据存储在大于 nvarchar(4000) 的 DataValue 中。但是,实际上只有很小一部分的行需要将此列作为 nvarchar(max)。我知道一旦 DataValue 超过 nvarchar(4000),在内部,sql 会将数据存储为 blob[?],从而大大增加了进行此更改所需的时间。(不确定以后读/写时间会受到怎样的影响)。

我想到了一些可能的选择......

  1. 将 DataValue 从 nvarchar(4000) 更改为 nvarchar(max) 并消耗进行更改所需的时间;不用担心只有 1% 的行正在使用MAX

  2. 除了 DataValue,添加一个 nvarchar(max) 的 DataValueXL 列并引入应用程序逻辑以根据数据的大小保存在适当的列中?(都标记为NULL

  3. 创建一个 FKed 到 UserDataId 的新表以仅存储大于 4000 的大数据值?

我应该和哪个——如果有的话——一起去?

谢谢

Rem*_*anu 10

一旦 DataValue 超过 nvarchar(4000),在内部,sql 会将数据存储为 blob

这是不正确的。SQL Server 将对最大和非最大类型使用行外存储。换句话说,您的 NVARCHAR(4000) 也可能存储在行外。实际存储位置将取决于该行是否适合页面以及和设置的sp_tableoption值的确切组合。large value types out of rowtext in row

最好的办法是将其更改为最大值。SQL 将尽可能将值存储在行中,从而提供快速访问。这使得应用程序编程更加简单,因为您不必根据大小处理实际位置(列)。如果您反对将第一个 max 类型列添加到表中,您应该只关心(例如,它会阻止在线重建操作),但您已经愿意添加一个,这样就不会有问题。

  • 从非最大类型切换到最大类型*必须*更新每一行并将数据从删除的列复制到新添加的列,因为非最大和最大类型不共享存储(行溢出与 LOB [分配单位](http://msdn.microsoft.com/en-us/library/ms189051.aspx))。从 2000 到 4000 的更改可以就地完成(仅限元数据),因为 nvarchar(2000) 和 nvarchar(4000) 共享相同的存储(行内或行溢出分配单元中)。另请参阅 http://rusanu.com/2011/10/20/sql-server-table-columns-under-the-hood/ (4认同)
  • 此外,在 SQL Server 2012 中,可以使用 LOB 列在线重建,因此某些用户的反对会比其他用户更快地消失。 (3认同)