`
dowhathowtodo
  • 浏览: 780308 次
文章分类
社区版块
存档分类
最新评论

关于数据库Varchar字段类型长度设计问题

 
阅读更多

关于数据库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没有这样的问题,它会根据每条记录字段的实际长度动态选择长度标识。


3、字段定义的长度对索引也有较大影响,MYSQL数据库的索引存储的长度都是定义的长度,不是实际字符的长度,这是一个非常大的问题,估计主要原因是为了实现简单,所以MYSQL在索引上会浪费大量的空间保存字符串。ORACLE虽然没有MYSQL所说的存储空间浪费问题,但是对索引长度还是有一定限制,8i官方文档说明单条记录索引信息的长度不能超过数据块大小的40%,9i中是75%,实际上也差不多,具体可以见jametong的http://www.dbthink.com/?p=20这篇文档,里面有详细的测试结果。如果你的数据块大小是8K,那么索引字段的定义长度不能超过6398,比如,你要给表上2个VARCHAR(4000)字段建组合索引,创建时会直接报错。另外索引组织表及在线重建索引(因为中间会临时创建一个索引组织表)允许的索引信息长度更小,只能是数据块大小的40%,实际中8K的数据块大小,要使用在线重建索引,那定义的长度不能超过3215。从以上可以看出,数据块大小为8K时,设计字段时如果要定义为VARCHAR(4000),那这个字段就不能考虑建立索引,因为即使能建上,也不能做在线重定义操作,DBA要进行索引维护时只能停止应用,这将对系统的可用性产生较大影响。关于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 level 1
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,所以要用自定义函数做函数索引需要特别注意一下,这可能会影响在线重建索引不能操作。
内置函数的索引长度根据函数决定,比如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) 。

我的新浪微博:http://weibo.com/yzsind

分享到:
评论

相关推荐

    GP数据库表结构转mysql库、oracle库 varchar类型字段长度批量处理excel_MYSQL_oracle_数据库

    oracle数据库表结构转gp数据库表结构、转mysql、数据库时表字段长度问题

    MySQL数据库varchar的限制规则说明

    varchar字段是将实际内容单独存储在聚簇索引之外,内容开头用1到2个字节表示实际长度(长度超过255时需要2个字节),因此最大长度不能超过65535。 b)编码长度限制 字符类型若为gbk,每个字符最多占2个字节,最大长度...

    仓库管理数据库设计.docx

    仓库管理数据库设计 专卖品牌管理数据结构分析草稿 表名 WZJBXX_1 关键字段 所属品牌,品牌类型, 名称,款式,型号,颜色 中文表名(功能描述) 序号 字段名称 字段描述 字段类型 长度 允许空 缺省值 1 品牌编号 int 4 ...

    BBS论坛系统数据库设计.doc

    后台用户管理(TAB_USER) "序号 "字段名称 "字段英文名 "数据类型"长度"PK(Y/N) "NULL(Y/N)"备注 " "1 "自增ID "id "int " "Y "N " " "2 "用户帐号 "usercode "varchar "20 " "N "登录用 " "3 "姓名 "username ...

    MySQL中字段类型char、varchar和text的区别

    在MySQL中,char、varchar和text类型的字段都可以用来存储字符类型的数据,char、varchar都可以指定最大的字符长度,但text不可以。 它们的存储方式和数据的检索方式也都不一样。 数据的检索效率是:char > varchar ...

    Mysql中varchar长度设置方法

    MySQL5的文档,其中对varchar字段类型这样描述:varchar(m) 变长字符串。M 表示最大列长度。M的范围是0到65,535。(VARCHAR的最大实际长度由最长的行的大小和使用的字符集确定,最大有效长度是65,532字节)。 为何会...

    jeecms数据库设计.doc

    1、jc_acquisition CMS采集表 编号 "字段 "名称 "类型 (长度) "主键 外键 "允许 为空 "初始值 "备注 " "1 "acquisition_id " "int(11) "P " " " " "2 "site_id " "int(11) "F " " " " "3 "channel_id " "int(11) ...

    网上购物系统数据库设计.doc

    系统管理员表 "表名:tb_Admin " "字段名 "数据类型 "长度 "主外键 "字段说明 "备注 " "AdminID "varchar "32 "主键 "管理员ID "非空 " "Password "varchar "32 "无 "管理员密码 "非空 " 会员区域表(tb_Area):...

    数据库设计规范(3).doc

    " "VARCHAR2(N) "Oracle数据库VARCHAR2类型,根据业" " "务数据特征定义适当的长度,定义成" " "偶数长度。 " "REAL、FLOAT、INTEGER、NUEBER "Oracle数据库必须使用NUEBER " "NUMBER(P,S)、NUMERIC (P, "Oracle...

    执法案件管理系统-数据库设计.docx

    字段(s) of "LAW_CASEINFO" Table 字段名 中文名 数据类型 主键 非空 外键 备注 ID 标识 BIGINT Yes NOT NULL No CASENO 案件编号 VARCHAR(50) No NULL No CASENAME 案件名称 VARCHAR(255) No NOT NULL No CASESOU ...

    php判断输入不超过mysql的varchar字段的长度范围

    如果你用strlen函数来判断,长度是11,正好超过了varchar的长度,但实际上确不是这样,如果直接到phpmyadmin里面执行insert语句,这条字符串是可以插入的! 对于数据库来说,它的长度是5,那么我们如何用PHP来得到这...

    在线购物系统数据库设计

    序号 字段 描述 类型和长度 主键 可空 默认值 1 groupid 自动编号 smallint(6) 是 否 无 2 classes 类型 varchar(30) 否 否 无 3 grouptitle 组名称 varchar(30) 否 否 无 4 groupdiscount 折扣 float 否 否 0 ...

    数据库设计指导规范.doc

    数据库设计指导规范 表和字段命名规范 表和字段命名的首字母大写,表必须要有主键,而且主键命名为Id,类型为varchar(3 6),因为在程序中我们是采用guid作为主键,注意:非主外键字段之外不得包含关键字 Id 外键...

    购物网站数据库设计(2).doc

    网站数据库设计 编辑:邢万欣 编辑时间:2009-11-17 个人用户用户表(yonghu) "字段 "类型(长度 "是否标识 "是否为空 "主/外键 "描述 " " ") " " " " " "uname "Varchar(50)"唯一验证 " " "登陆名称 " "upass ...

    超市管理系统(数据库设计、E-R图).doc

    数据库表的设计 表1.1 用户表 "字段名 "字段类型 "长度 "主/外键 "字段值约束 "对应中文名 " "UserPassword "Varchar "20 " "Not null "用户密码 " "UserIdentity "Varchar "10 " "Not null "用户身份 " "UserStatus...

    在线考试系统数据库设计.doc

    department) 单选题表(TB schoose) 多选题表(Tb_mchoose) "管理员信息表(tb_Admin) " "字段名 "数据类型 "长度 "主键 "描述 " "ID "Int "4 "是 "系统编号 " "AdminID "Varchar "50 "否 "管理员编号 " "AdminName ...

    数据库设计原则.pdf

    数据库设计原则 数据库设计原则 1、在创建数据表的时候,对于字符串类型的字段,如果明确知道字段的长度,就⽤char类型,否则⽤varchar。char类型查询速度更快,但 会浪费存储空间 字符串char和varchar的区别在于两...

    数据库物理设计.pdf

    字段长度⽐datetime⼩。 缺点:使⽤不⽅⾯,要进⾏函数转换才能看懂。 限制:只能存储到2038-1-19 11:14:07。即2的32次⽅ 2、需要存储的时间粒度。 年 ⽉ ⽇ ⼩时 分 秒 周 其他: 如何选择主键: 1、区分业务主键和...

    数据库设计命名规范.docx

    注:在MySQL5.0以上的版本中,varchar数据类型的长度支持到了65535,也就是说可以存放65532个字节的数据,起始位和结束位占去了3个字节 建议在大 数表中含有如下字段 数据库设计命名规范全文共6页,当前为第5页。...

Global site tag (gtag.js) - Google Analytics