2010-08-11 122 views
3

假设我有一个列name varchar(20)的表,我存储了一行name =“abcdef”。这不会使varchar2效率低下?

INSERT INTO tab(id, name) values(12, 'abcdef'); 

如何为name内存分配在这种情况下怎么办?

有两种方法我能想到的:

一)

20字节分配,但只用6。就内存分配而言,在这种情况下,varchar2char相比没有任何显着优势。

B)

只有6个字节被分配。如果是这样的话,我addded一对夫妇更行这一个之后,

INSERT INTO tab(id, name) values(13, 'yyyy'); 
INSERT INTO tab(id, name) values(14, 'zzzz'); 

,然后我做了更新,

UPDATE tab SET name = 'abcdefghijkl' WHERE id = 12; 

哪里的DBMS获取所需的额外6个字节从?可能存在下一个6字节不空闲的情况(如果最初仅分配了6个字节,则可能已经为其他字节分配了下一个字节)。

除了将排移到新位置之外,还有别的方法吗?即使移位也会成为索引组织表格的问题(对于堆组织的表格来说可能没问题)。

+1

这是依赖于实现的,但很可能当您更新时,新行将写入与旧行完全不同的位置。即使没有varchar也是如此。 – hobbs 2010-08-11 09:26:48

回答

1

有可能取决于你所使用的RDBMS的变化,但一般:

只有你在varchar现场存储的实际数据进行分配。大小只是允许的最大值,并不是分配多少。

我认为这也适用于char字段,在某些系统上。可变大小数据类型的处理效率足够高,以至于在分配最大值时不再有任何收益。

如果更新记录以使其需要更多空间,则同一分配块内的记录向下移动,如果记录不再适合该块,则分配另一个块并将记录分配到块之间。这意味着记录在分配块内是连续的,但块不必在磁盘上连续。

+0

在Oracle和DB2系统上,NOT NULL CHAR(n BYTES)字段将始终消耗n个字节。 – 2010-08-12 17:36:35

1

它当然不会分配更多的空间,然后需要,这将打败使用可变长度类型的点。

在你提到的情况下,我会认为下面的行将不得不在页面上向下移动,或许这是优化的。我真的不知道确切的细节,也许别人可以进一步评论。

1

编辑出于某种原因,我认为这被标记为Microsoft SQL Server。我想答案仍然是相关的,虽然

这就是为什么official recommendation

  • 使用CHAR时,列数据项的大小是一致的。
  • 当列数据条目的大小相差很大时,使用varchar。
  • 当列数据条目的大小变化很大时,使用varchar(max),大小可能为 超过8,000字节。

这是在设计表结构时需要考虑的因素。可能你需要考虑在这个计算中更新vs读取的频率太

值得注意的是,对于char a NULL值仍然使用所有的存储空间。 Management Studio中有一个名为SQL Internals Viewer的插件,可让您轻松查看行的存储方式。

1

这可能严重依赖数据库。

虽然有几点:MVCC观察数据库实际上并未更新磁盘或内存高速缓存中的数据。他们用更新的数据插入一个新行,并将旧行标记为从某个事务中删除。过了一段时间后,删除的行对任何事务都不可见并且被回收。

对于存储空间问题,它通常是在的1-4 bytes of header + data (+ padding)

在字符的情况下的形式,该数据被填充以达到足够的长度。在varchar或text的情况下,标题存储了后续数据的长度。

+0

您对MVCC数据库的工作方式的描述与Oracle的工作方式不一致。 Oracle会在适当位置更新该行,同时编写信息以撤销回滚段或撤消表中的更改,以便可以读取以前的版本。以及写入重做日志,以便在发生故障时不会丢失更改。 – 2010-08-16 19:43:39

1

鉴于问题标题中的VARCHAR2,我假设您的问题集中在Oracle。在Oracle中,可以使用PCTFREE子句为数据块内的行扩展保留空间。这可以帮助减轻更新使行更长的影响。但是,如果Oracle在块内没有足够的可用空间来写回行,则它所做的操作称为行迁移;它只在磁盘上留下原始地址(因此它不一定需要更新索引),但不是将数据存储在原始位置,而是存储指向该行新地址的指针。

如果大量的行已迁移,那么在索引严重访问表的情况下,这会导致性能问题,因为它会添加额外的I/O以满足查询。