SQL varchar列长度的最佳实践

每次都build立一个新的SQL表或为现有的表添加一个新的varchar列,我想知道一件事:什么是length的最佳值。

所以,可以说,你有一个名为typesvarchar的列。 所以,你必须select长度。 我想不出一个名字> 20个字符,但你永远不会知道。 但是不是用20,我总是凑到下一个2 ^ n的数字。 在这种情况下,我会select32作为长度。 我这样做,因为从计算机科学家的angular度来看,数字2 ^ n比其他数字看起来更even ,我只是假设下面的架构可以处理这些数字比其他数字略好。

另一方面,例如,当您select创build一个varchar列时,MSSQL服务器将默认长度值设置为50。 这让我思考。 为什么50? 是只是一个随机数,还是基于平均列长度,还是什么?

也可能是 – 也可能是 – 不同的SQL服务器实现(如MySQL,MSSQL,Postgres等)具有不同的最佳列长度值。

没有DBMS我知道有任何“优化”,将使一个2^n长度的VARCHAR执行比max长度不是2的幂更好。

我认为早期的SQL Server版本实际上处理了长度为255的VARCHAR ,而不是最大长度VARCHAR 。 我不知道这是否仍然如此。

对于几乎所有的DBMS,所需的实际存储空间仅取决于您input的字符数,而不是您定义的max长度。 所以从存储的angular度来看(也可能是性能方面),不pipe你声明一个列为VARCHAR(100)还是VARCHAR(500) ,都没有什么区别。

您应该将为VARCHAR列提供的max长度看作一种约束(或业务规则),而不是技术/物理事物。

对于PostgreSQL来说,最好的设置是使用没有长度限制的text ,并使用CHECK CONSTRAINT来限制字符的数量。

如果这个需求改变,改变检查约束比改变表要快得多(因为表不需要被重写)

Oracle和其他应用程序也是如此 – 在Oracle中,它将是VARCHAR(4000)而不是text

我不知道SQL Server中是否存在VARCHAR(max)和例如VARCHAR(500)之间的物理存储区别。 但显然,与varchar(8000)相比,使用varchar(max)时会有性能影响。

看到这个链接 (由Erwin Brandstetter发表作为评论)

编辑2013-09-22

对于bigown的评论:

在9.2之前的Postgres版本中(当我写下最初的答案的时候,这个版本是不可用的)对列定义的改变确实重写了整个表,例如见这里 。 从9.2开始,现在不再是这种情况了,一个快速testing证实,增加一个有120万行的表的列大小的确只花了0.5秒。

对于Oracle来说,这似乎也是真实的,从修改大表的varchar列所需的时间来判断。 但我找不到任何参考。

对于MySQL 的手册说: “ 在大多数情况下, ALTER TABLE使原始表的临时副本 ”。 我自己的testing证实:在一个有120万行的ALTER TABLE上运行一个ALTER TABLE (和我在testingPostgres时一样)来增加一个列的大小需要1.5分钟。 但在MySQL中,您不能使用“解决方法”来使用检查约束来限制列中的字符数。

对于SQL Server,我找不到一个清晰的声明,但是增加一个varchar列的大小的执行时间(同样是从上面的120万行的表)表示没有重写发生。

编辑2017-01-24

似乎我(至less部分)错误的SQL Server。 看到来自Aaron Bertrand的这个答案,它显示了nvarcharvarchar列的声明长度对性能有很大的影响。

VARCHAR(255)和VARCHAR(2)占用的磁盘空间量完全相同 ! 所以限制它的唯一理由是如果你有一个特定的需要,它是较小的。 否则,使他们全部255。

具体来说,在sorting时,较大的柱子会占用更多的空间,所以如果这样做会损害性能,那么你需要担心它,并使它们变小。 但是,如果你只从表中select1行,那么你可以把它们全部设置为255,这并不重要。

请参阅: 什么是MySQL的最佳varchar大小?

最好的价值是对底层领域定义的数据是正确的。

对于某些域, VARCHAR(10)适用于Name属性,对于其他域VARCHAR(255)可能是最佳select。

添加到a_horse_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 

不要忘记长度字节和可空字节,所以:

name varchar(100) not null将是1个字节(长度)+最多100个字符(latin1)

name varchar(500) not null将是2个字节(长度)+最多500个字符(拉丁文)

name varchar(65533) not null将是2个字节(长度)+最多65533个字符(latin1)

name varchar(65532)将是2个字节(长度)+最多65532个字符(latin1)+ 1个空字节

希望这可以帮助 :)

每当我build立一个新的SQL表时,我都会感觉到2 ^ n更“平等”的相同方式…但是总结这里的答案,仅仅通过定义varchar(2 ^ n)甚至varchar(MAX)。

也就是说,在设置高varchar()限制时,您仍然应该考虑对存储和性能的潜在影响。 例如,假设您创build一个varchar(MAX)列来保存带有全文索引的产品描述。 如果99%的描述只有500个字符长,然后突然之间你会得到一个用维基百科文章replace所述描述的人,你可能会注意到意想不到的显着存储和性能命中。

Bill Karwin另外要考虑的是 :

有一个可能的性能影响:在MySQL中,临时表和MEMORY表将VARCHAR列存储为固定长度的列,填充为最大长度。 如果你devise的VARCHAR列比你所需要的最大的尺寸大得多,你会消耗更多的内存。 这会影响caching效率,sorting速度等

基本上,只是想出一个稍微大一点的合理的业务约束和错误。 正如@onedayhen指出的,英国的姓氏通常在1-35个字符之间。 如果你决定使用varchar(64),那么你不会伤害任何东西……除非你存储这个家族的名字 ,据说长达666个字符。 在这种情况下,也许varchar(1028)更有意义。

如果有帮助,这里是什么varchar 2 ^ 5到2 ^ 10可能看起来像是如果填充:

 varchar(32) Lorem ipsum dolor sit amet amet. varchar(64) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie varchar(128) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie vestibulum massa. Nullam dignissim elementum molestie. Vehiculas varchar(256) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie vestibulum massa. Nullam dignissim elementum molestie. Vehiculas velit metus, sit amet tristique purus condimentum eleifend. Quis que mollis magna vel massa malesuada bibendum. Proinde tincidunt varchar(512) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie vestibulum massa. Nullam dignissim elementum molestie. Vehiculas velit metus, sit amet tristique purus condimentum eleifend. Quis que mollis magna vel massa malesuada bibendum. Proinde tincidunt dolor tellus, sit amet porta neque varius vitae. Seduse molestie lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et mollis diam pretium gravida. In facilisis vitae tortor id vulput ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie varchar(1028) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie vestibulum massa. Nullam dignissim elementum molestie. Vehiculas velit metus, sit amet tristique purus condimentum eleifend. Quis que mollis magna vel massa malesuada bibendum. Proinde tincidunt dolor tellus, sit amet porta neque varius vitae. Seduse molestie lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et mollis diam pretium gravida. In facilisis vitae tortor id vulput ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie dapibus leo lobortis eleifend. Vivamus vitae diam turpis. Vivamu nec tristique magna, vel tincidunt diam. Maecenas elementum semi quam. In ut est porttitor, sagittis nulla id, fermentum turpist. Curabitur pretium nibh a imperdiet cursus. Sed at vulputate este proin fermentum pretium justo, ac malesuada eros et Pellentesque vulputate hendrerit molestie. Aenean imperdiet a enim at finibus fusce ut ullamcorper risus, a cursus massa. Nunc non dapibus vel Lorem ipsum dolor sit amet, consectetur Praesent ut ultrices sit 

总是与您的业务领域的专家检查。 如果那是你,找一个行业标准。 例如,如果有问题的域名是自然人的姓氏,那么对于英国公司,我会去英国的Govtalk数据标准目录获取个人信息,并发现一个姓氏将在1到35个字符之间。

我最近没有检查过这个,但是我知道在过去的Oracle中JDBC驱动程序会在查询执行期间保留一大块内存来保存返回的结果集。 内存块的大小取决于列定义和获取大小。 所以varchar2列的长度会影响保留多less内存。 这导致了我几年前严重的性能问题,因为我们总是使用varchar2(4000)(当时的最大值),垃圾收集的效率比现在低得多。