每次建立一个新的SQL表或向现有表添加一个新的varchar列时,我都想知道一件事:长度的最佳值是多少。
假设,你有一个列名为name类型为varchar。所以,你必须选择长度。我想不出一个20个字符的名字,但你永远不会知道。但不是用20,我总是四舍五入到下一个2^n。在这种情况下,我将选择32作为长度。我这样做,是因为从计算机科学家的角度来看,2^n这个数字在我看来比其他数字更均匀,我只是假设下面的架构可以比其他数字更好地处理这些数字。
另一方面,以MSSQL服务器为例,当您选择创建varchar列时,将默认长度值设置为50。这让我开始思考。为什么50 ?它只是一个随机数,还是基于平均列长,还是什么?
也可能是——或者可能是——不同的SQL服务器实现(如MySQL, MSSQL, Postgres,…)有不同的最佳列长度值。
添加到a_horis_with_no_name的答案中,您可能会发现以下内容令人感兴趣……
是否将列声明为没有任何区别
VARCHAR(100)或VACHAR(500)。
-- try to create a table with max varchar length
drop table if exists foo;
create table foo(name varchar(65535) not null)engine=innodb;
MySQL Database Error: Row size too large.
-- try to create a table with max varchar length - 2 bytes for the length
drop table if exists foo;
create table foo(name varchar(65533) not null)engine=innodb;
Executed Successfully
-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65533))engine=innodb;
MySQL Database Error: Row size too large.
-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65532))engine=innodb;
Executed Successfully
不要忘记长度字节(s)和可空字节,这样:
Name varchar(100) not null将是1字节(长度)+最多100个字符(latin1)
Name varchar(500) not null将是2字节(长度)+最多500个字符(latin1)
Name varchar(65533) not null将是2字节(长度)+ 65533个字符(latin1)
名称varchar(65532)将是2个字节(长度)+最多65532个字符(latin1) + 1个空字节
希望这对你有所帮助。
我所知道的DBMS中没有任何“优化”可以使长度为2^n的VARCHAR比最大长度不是2的VARCHAR性能更好。
我认为早期的SQL Server版本实际上对待长度为255的VARCHAR与最大长度更高的VARCHAR是不同的。我不知道现在是不是还是这样。
对于几乎所有的DBMS,实际需要的存储空间仅由您放入其中的字符数决定,而不是您定义的最大长度。因此,从存储的角度(很可能也是性能的角度)来看,将列声明为VARCHAR(100)还是VARCHAR(500)没有任何区别。
您应该看到为VARCHAR列提供的最大长度是一种约束(或业务规则),而不是技术/物理方面的东西。
对于PostgreSQL,最好的设置是使用没有长度限制和CHECK约束的文本,CHECK约束限制了您的业务所需的字符数量。
如果需求发生变化,更改检查约束比更改表要快得多(因为表不需要重写)。
同样的方法也适用于Oracle和其他应用程序——在Oracle中,它将是VARCHAR(4000)而不是文本。
我不知道在SQL Server中的VARCHAR(max)和VARCHAR(500)之间是否有物理存储的区别。但是,使用varchar(max)与使用varchar(8000)相比,显然存在性能影响。
请看这个链接(由Erwin Brandstetter作为评论发布)
编辑2013-09-22
关于bigown的评论:
在9.2之前的Postgres版本中(当我写初始答案时还不可用),对列定义的更改确实重写了整个表,参见这里的例子。从9.2开始,这种情况不再存在,快速测试证实,对于一个有120万行的表,增加列大小确实只需要0.5秒。
对于Oracle来说,从修改一个大表的varchar列所花费的时间来看,这似乎也是正确的。但我找不到任何相关的参考资料。
对于MySQL,手册上说:“在大多数情况下,ALTER TABLE对原始表进行临时复制”。我自己的测试也证实了这一点:在一个有120万行的表上运行一个ALTER TABLE(与我使用Postgres进行的测试相同)来增加一个列的大小需要1.5分钟。然而,在MySQL中,你不能使用“变通方法”来使用检查约束来限制列中的字符数。
对于SQL Server,我找不到一条明确的语句,但增加varchar列大小的执行时间(同样是上面的120万行表)表明没有发生重写。
编辑2017-01-24
看来我对SQL Server的看法(至少部分)是错误的。Aaron Bertrand给出的答案表明,nvarchar或varchar列的声明长度对性能有很大影响。