【问题标题】:Sql Server row size limit and table designSql Server 行大小限制和表设计
【发布时间】:2013-11-26 14:20:30
【问题描述】:

我在 SQL Server 2008 上有这个查询

CREATE TABLE MediaLibrary
(
MediaId bigint NOT NULL IDENTITY (1, 1),
MediaTypeId smallint NOT NULL,
ImageNameByUser nchar(100) NULL,
GeneratedName uniqueidentifier NOT NULL,
UploadedByUserId uniqueidentifier NOT NULL,
UploadedDate date NOT NULL,
ProfilePhoto bit NOT NULL,
PublicPhoto bit NOT NULL,
AppointmentId bigint NULL,
OriginalImage nchar(1000) NULL,
ThumbImage nchar(1000) NULL,
MediumImage nchar(1000) NULL,
LargeImage nchar(1000) NULL,
UrlThumb nchar(1000) NULL,
UrlMedium nchar(1000) NULL,
UrlLarge nchar(1000) NULL,
InactiveReasonId smallint NULL,
InactiveDate datetime NULL
)  ON [PRIMARY]
GO

当我尝试创建表时出现此错误

创建或更改表“MediaLibrary”失败,因为最小行大小为 14273,包括 9 字节的内部开销。这超出了允许的最大表行大小 8060 字节。

我知道我达到了行大小的限制,但这不是一张大桌子,所以我想知道这不是一个好的设计吗?

当我将nchar(1000) 更改为varChar(1000) 时,表格保存得很好。我担心的是,一旦数据实际保存到表中,我将再次达到行大小限制。

【问题讨论】:

  • nchar(1000) 是一个非常糟糕的主意 - 它会总是使用 2000 字节的存储空间 - 即使你只在里面存储“a”它。 nchar(n) 是简短的(最多 3 个,可能是 5 个字符)字符串,例如ISO货币代码等;但对于较长的文本 sn-ps,您应该始终使用 (n)varchar(x) 数据类型,它只存储真正存在的内容!

标签: sql-server database-design sql-server-2008-r2


【解决方案1】:

假设您不打算填充所有列,您需要使用 nvarchar(或只是 varchar)而不是 nchar(或 char)。原因是nchar(1000) 需要保留 2000 个字节,无论您是否要使用它。这不适用于 varchar/nvarchar。

现在,如果您可能在这些列中的每一列中包含 1000 个字符,那么无论您使用哪种数据类型,它都无法正常工作。原因是 SQL Server 中的基本存储元素是 8K 页。因此,不可能存储超过 ~8K 的行(存在一些页眉开销以及可能使用的其他位,具体取决于列中的数据类型)。解决方法通常是:

  • varchar(max) - 它可以将不适合行外的数据存储为 blob,但这样做会产生性能开销,并且可能会引入一些限制,例如执行在线重建的能力
  • 更改表结构,以便将这些 URL 作为单独的行存储在单独的表中。示例:

    CREATE TABLE dbo.Media
    (
      MediaID BIGINT IDENTITY(1,1) PRIMARY KEY,
      MediaTypeID SMALLINT NOT NULL,
      ImageNameByUser NVARCHAR(100) NULL, -- should also not be nchar
      GeneratedName UNIQUEIDENTIFIER NOT NULL,
      UploadedByUserId UNIQUEIDENTIFIER NOT NULL,
      UploadedDate date NOT NULL,
      ProfilePhoto bit NOT NULL,
      PublicPhoto bit NOT NULL,
      AppointmentId bigint NULL,
      InactiveReasonId smallint NULL,
      InactiveDate datetime NULL
    );
    
    CREATE TABLE dbo.URLTypes
    (
      URLTypeID TINYINT NOT NULL PRIMARY KEY,
      Description NVARCHAR(32) NOT NULL UNIQUE
    );
    
    INSERT dbo.URLTypes VALUES(1,'OriginalImage'),(2,'ThumbImage'),...;
    
    CREATE TABLE dbo.MediaURLs
    (
      MediaID BIGINT NOT NULL FOREIGN KEY REFERENCES dbo.Media(MediaID),
      URLTypeID TINYINT NOT NULL FOREIGN KEY REFERENCES dbo.URLTypes(URLTypeID),
      URL VARCHAR(2048) NOT NULL
    );
    

顺便说一句,您真的需要为 URL 支持 Unicode 吗?

【讨论】:

  • 没有。 URL 只是服务器端文件位置的副本。我可能只需要保存一个或另一个。这也会把 3 行从桌子上敲下来。也是的,每一列都有指向拇指、中、大的路径。我已经填充了 1000 个,这也可能是太多的填充,但我认为拥有更多而不是更少。由于我知道文件夹结构并且我可以获取托管服务器上的路径,因此我可以将其倒数到更近的填充范围。
  • 编辑是我想去的另一种方式。谢谢!
  • 最后一个问题是最好存储 URL 而不是服务器路径。好像杀过头了。
  • 如果服务器路径总是一样的,似乎很浪费。关于您存储的内容,我没有足够的信息来进行真正的评估。
  • 现在他们会非常匹配。所以很浪费。但是通过编辑的这种设计,如果需要,可以很容易地扩展以保存服务器位置。感谢您清除它。
猜你喜欢
  • 2011-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多