这怎么不使varchar2效率低下?

时间:2010-08-11 08:58:56

标签: sql database database-design rdbms varchar

假设我有一个包含列name varchar(20)的表,并且我存储了一行名为=“abcdef”的行。

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

在这种情况下,name的内存分配情况如何?

我能想到两种方式:

A)

分配了20个字节,但只使用了6个字节。在这种情况下,varchar2在内存分配方面没有char的任何明显优势。

b)中

仅分配了6个字节。如果是这种情况,我在这之后添加了几行,

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个字节,则可能已分配了下一个字节别的东西)。

除了将行转移到新地方之外,还有其他方法吗?在索引组织表的情况下,即使转换也是一个问题(堆组织表可能没问题)。

5 个答案:

答案 0 :(得分:1)

当然不需要分配更多的空间,这样就无法使用变长类型。

在你提到的情况下,我认为下面的行必须在页面上向下移动,也许这会以某种方式进行优化。我真的不知道确切的细节,也许其他人可以进一步评论。

答案 1 :(得分:1)

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

这就是official recommendation

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

在设计表结构时需要考虑的是权衡。在这个计算中你可能还需要考虑更新频率和读数

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

答案 2 :(得分:1)

根据您使用的rdbms,可能会有不同的变化,但通常是:

仅分配存储在varchar字段中的实际数据。大小只是允许的最大值,而不是分配的大小。

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

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

答案 3 :(得分:1)

这可能与数据库有很大关系。

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

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

的形式

在字符的情况下,数据被填充以达到足够的长度。对于varchar或text,标头存储后续数据的长度。

答案 4 :(得分:1)

鉴于问题标题中的VARCHAR2,我认为您的问题主要围绕Oracle。在Oracle中,您可以使用PCTFREE子句为数据块中的行扩展保留空间。这可以帮助减轻更新使行更长的影响。

但是,如果Oracle在块中没有足够的可用空间来写回行,那么它的行为称为行迁移;它将原始地址留在磁盘上(因此它不一定需要更新索引),但它不是将数据存储在原始位置,而是存储指向该行的新地址的指针。

如果已经迁移了大量行,则索引会严重访问表时会导致性能问题,因为它会添加额外的I / O以满足查询。