关于SQL数据库Varchar字符串类型长度设计问题(转载)
为什么要合理的设计数据库字段数据类型的长度?
个⼈观点:⼀个是降低物理上的存储空间,⼀个是提⾼数据库的处理速度,还有⼀个附带功能是能校验数据是否合法。
现代数据库⼀般都⽀持CHAR与VARCHAR字符型字段类型,CHAR是⽤来保存定长字符,存储空间的⼤⼩为字段定义的长度,与实际字符长度⽆关,当输⼊的字符⼩于定义长度时最后会补上空格。VARCHAR是⽤来保留变长字符,在数据库中存储空间的⼤⼩是实际的字符长度,不会像CHAR⼀样补上空格,这样占⽤的空间更少。
从以上特点来看,VARCHAR⽐CHAR有明显的优势,因此⼤部份数据库设计时都应该采⽤VARCHAR类型。那为什么还需要CHAR类型呢,个⼈认为有以下⼏个原因:
1、为了跟以前版本的数据库进⾏⼀个兼容,因为很久以前数据库只⽀持CHAR类型,有些应⽤的业务逻辑也只是针对CHAR类型设计的,所以数据库软件也就⼀直保留CHAR类型。
2、CHAR类型是定长的,⼀些数据库可以在每条记录中不存储字段长度信息,这样可以节省部份空间,也可以⽅便做⼀些内存对齐提⾼性能,但个⼈认为这带来的性能提升⾮常微⼩,⾄少ORACLE数据库是
没有意义的。
3、还有说法是有些数据经常修改,长度可能变化,会引起碎⽚,采⽤CHAR就不会产⽣碎⽚,这个说法⽐较多,但我认为既然长度会变化,那⽤VARCHAR更能节省内存与存储空间来提升性能,只要数据块预留的空间没有问题,采⽤VARCHAR性能更好。
对于ORACLE数据库,我不到充⾜的理由来使⽤CHAR类型,⽽且CHAR还会带来讨厌的空格,有些⽂章说MYSQL的MYISAM存储引擎在和长度固定的情况下CHAR⽐VARCHAR 好,这个没有测试过,不太了解。
由于VARCHAR是变长存储,那么很多⼈会有疑问,⽐如STATUS字段定义VARCHAR(10)与VARCHAR(1000)有什么区别,反正是变长的,存储空间都⼀样,省得以后要加长⼜要改变字段定义。下⾯说⼀下我的理解:
1、字段长度是数据库⼀种约束,可以保证进⼊数据库的数据符合长度要求,定义合理的字段长度可以减少⼀部份⾮法数据进⼊,⽐如:我们业务中STATUS只
有‘NEW’,‘DELETE’,‘CLOSE’3种状态,使⽤VARCHAR(5)保存,这样可以有效的减少⾮法数据进⼊,定义合理的长度也可以让⼈容易理解字段的⽤途,试想⼀下,如果你所有的字符字段长度都是VARCHAR(4000)会是什么样的情况。
2、VARCHAR的字段长度虽然对数据存储没有太⼤影响,但对特定的数据库还是有⼀些细微差别,⽐如MYSQL中定义的长度如果⼩于255,字段长度⽤1个字节表⽰,如果超过255,字段的长度将固定⽤2个字节表⽰。如果你的业务数据最⼤长度只有10,但定义长度为256则每条记录会多浪费了⼀个字节来存储长度。ORACLE没有这样的问题,它会根据每条记录字段的实际长度动态选择长度标识。
SQL>create table test1
2 (
3 c1 varchar2(4000),
4 c2 varchar2(4000),
5 c3 varchar2(4000)
6 )
7 ;
Table created
SQL>create index test1_ind1 on TEST1 (c1);
Index created
SQL>alter index test1_ind1 rebuild online;
alter index test1_ind1 rebuild online
ORA-00604: error occurred at recursive SQL level1
ORA-01450: maximum key length (3215) exceeded
SQL>create index test1_ind2 on TEST1 (c2, c3);
create index test1_ind2 on TEST1 (c2, c3)
ORA-01450: maximum key length (6398) exceeded
SQL>
关于ORACLE的索引长度还有⼀些特别的规则,⽐如⾃定义函数返回的字符定义长度固定是4000,所以要⽤⾃定义函数做函数索引需要特别注意⼀下,这可能会影响在线重建索引不能操作。sql软件长什么样
内置函数的索引长度根据函数决定,⽐如UPPER这种不改变长度的就是索引字段定义的长度,SUBSTR这种会改变长度要根据函数截取长度决定。
NUMBER类型字段的长度固定是22。
DATA类型字段的长度固定是7。
索引默认是升序,如果要降序建的索引长度是字段定义长度*1.5+1。
MYSQL对索引长度限制⽐较复杂,每种版本及存储引擎都不⼀样,如下是MYSQL5.1.58测试的结果:
INNODB的最⼤总长度是3072字节,单个字符字段是767字节,如果字段长度⼤于767则⾃动截取前767个字符。
MYISAM最⼤总长度是1000字节,单个字符字段是1000字节。
MEMORY的最⼤总长度是3072字节,单个字符字段是3072字节。
4、变长字段定义的长度虽然不会影响服务器数据空间⼤⼩,但是对于客户端的内存有影响,因为客户
端在⽤SQL从数据库读取数据时,⾸先会取到字段定义的长度,然后分配⾜够的内存,也就是说如果你定义的字段长度是1K,实际长度是10字节,要取1K记录,那客户端会分配1MB的内存,但只保存了10K有效数据。这将会⽐较严重的浪费客户端内存。特别是⼀些⾼并发或者是取⼤量数据的场景,容易产⽣内存溢出。
5、关于字段长度对齐的问题,有些设计⼈员喜欢定义字段的长度为4或者8的倍数,如16,32,64,128之类的,理由是可以做到内存对齐,对于这个问题我没有深⼊分析过,个⼈认为必要性不⼤,也没看到过这种优化能提升性能的案例。如果⼀个VARCHAR(1)定义为VARCHAR(4)反⽽浪费内存与存储,实际上我看到在ORACLE jdbc驱动中会将所有的字符类型数据保存在⼀个⼤的char[]中,把所有NUMBER与DATE类型放在另⼀个char[]中,这样整合后都不清楚如何内存对齐了。
综上所述:VARCHAR类型字段长度不能随便定义,并不是越⼤越好,还是需要根据实际业务数据定义⼀个合适的长度。我个⼈对于⼀些可以完全预估的长度就按实际长度定义,⽐如年⽉、状态、标记之类的信息。对于不确定长度的业务数据如NAME、STYLE之类的信息定义⼀个合理值,如VARCHAR(20),VARCHAR(30) 之类。对于描述性或备注性的信息,这些字段也确定不会有索引,长度也不可预知,所以留更⼤的长度,避免以后经常进⾏长度调整,如VARCHAR(1024),或者直接VARCHAR2(4000) 。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论