varchar 性能影响

M A*_*ifi 6 performance sql-server-2008 varchar

之前已经问过这个问题(在 SQL Server 2008 中使用 varchar 的速度影响),但答案不够详细,令我满意。诚然,这不是当前的问题,主要是针对我的教育。

但是,我将尝试将其作为我正在做的一些当前数据库模式工作的具体示例;

选项 A

CREATE TABLE [VMware].[TblHostSystem](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    <snip/>
    [PowerStateID] [int] NOT NULL
)

ALTER TABLE [VMware].[TblHostSystem]  WITH
CHECK ADD  CONSTRAINT [FK_TblHostSystem_TblPowerState]
FOREIGN KEY([PowerStateID])
REFERENCES [VMware].[TblPowerState] ([ID])
GO

CREATE TABLE [VMware].[TblPowerState](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [PowerState] [varchar](50) NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

选项 B

CREATE TABLE [VMware].[TblHostSystem](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    <snip/>
    [PowerState] [varchar](50) NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

如果我选择了选项 B(正如模式的前任作者所做的那样),由于主机的功能会经常变化,这会产生什么样的流失?

一些我认为是真实的陈述,

  1. Varchar 存储在 MSSQL 2008 上的同一行/页中。
  2. Varchars 没有填充?

所以我的问题是,当将第二个示例中的 PowerState 从“powerOn”(20 字节)更新为“powerOff”(22 字节)时,数据库需要做什么?

  1. 将行移动到新页面,因为现在有空间容纳额外的 2 个字节?
  2. 将当前行之后的所有内容向前移动 2 个字节,因为 ID 上有一个簇索引并且必须保持磁盘上的顺序?
  3. 以上都不是,数据库实际上分配了 102 个字节(varchar(50) 的最大可能大小)并且大部分时间都有大量可用空间来适应这种变化而不会产生大量流失?
  4. 将 varchar(50) 列拆分到另一个页面以避免由 1 和 2 引起的大量流失,并且它不会填充为 3,但这意味着每行可能锁定多个页面并且从磁盘中读取两次(可能)而不是一个。

希望详细了解幕后发生的事情!

JNK*_*JNK 5

第一个问题——

  • 是的,它们通常存储在页面上(对于非(MAX)值)
  • 它们没有被填充,但每行有 2 个字节的开销来存储字段的长度

1 -取决于页面是否已满。它很可能适合当前页面。行的标题记录也需要更新以更新字段的长度。

2 - 数据只会在页面级别为插入或更新重新排列,因此不会移动其他任何内容。如果它适合您当前的页面,它将,否则将有一个页面拆分。

3 - 据我所知,从来没有varchar- 如果你想要这种行为,你可以CHAR改为。

4 - 仅当值超过页面上的空间时。

至于设计本身...

使用id代替 a肯定会获得更好的性能varchar

  • int 或 smallint 比您的字符串小几个数量级。
  • 索引查找在整数上比在字符串上效率高得多
  • 存储在页面上的数据将保持一致且小得多
  • SQL 喜欢键!当您使用PK/FK关系时,可以进行很多优化,因为引擎可以推断出有关重复/不同值等的一些元数据。