我有一个contacts
包含字段,如表postcode
,first name
,last name
,town
,country
,phone number
等等,所有这些都被定义为VARCHAR(255)
即使没有这些领域都不会接近有255个字符.(如果你想知道,就是这样,因为Ruby on Rails迁移VARCHAR(255)
默认情况下将字符串字段映射到我并且我从不打扰覆盖它).
由于VARCHAR只会领域的实际字符的数目存储(连同字段长度),是否有任何明显的优势(性能或其他方式)使用,比方说,VARCHAR(16)
在VARCHAR(255)
?
此外,大多数这些字段都有索引.字段上的较大VARCHAR大小是否会影响索引的大小或性能?
仅供我使用MySQL 5.
在存储中,VARCHAR(255)
足够聪明,只能存储给定行所需的长度,而不像CHAR(255)
存储255个字符.
但是由于你用MySQL标记了这个问题,我将提到一个特定于MySQL的提示:当行从存储引擎层复制到SQL层时,VARCHAR
字段被转换为CHAR
使用固定宽度行的优势.因此,内存中的字符串将填充到声明VARCHAR
列的最大长度.
当您的查询隐式生成临时表时,例如在排序时GROUP BY
,这可能会占用大量内存.如果VARCHAR(255)
对不需要那么长的数据使用大量字段,这可能会使临时表非常大.
您可能还想知道这种"填充"行为意味着使用utf8字符集声明的字符串会填充每个字符三个字节,即使对于存储单字节内容的字符串(例如ascii或latin1字符)也是如此.同样,utf8mb4字符集会使字符串在内存中填充每个字符四个字节.
所以VARCHAR(255)
在utf8中存储一个像"No opinion"这样的短字符串需要在磁盘上占用11个字节(10个低字符集字符,加上一个字节用于长度),但它在内存中需要765个字节,因此在临时表或排序结果中.
我帮助MySQL用户经常在不知不觉中创建1.5GB临时表并填满他们的磁盘空间.他们有很多VARCHAR(255)
专栏,实际上存储了非常短的字符串.
最好根据您要存储的数据类型定义列.正如其他人提到的那样,它有助于强制执行与应用程序相关的约束.但它有物理上的好处,以避免我上面描述的内存浪费.
当然,很难知道最长的邮政地址是什么,这就是为什么很多人选择的长度VARCHAR
肯定比任何地址长.并且255是惯用的,因为它是VARCHAR
可以用一个字节编码长度的a的最大长度.这也是VARCHAR
MySQL早于5.0 的最大长度.
除了设置varchar大小的大小和性能考虑因素(可能更重要的是,随着存储和处理每秒变得更便宜),使用varchar(255)"仅仅因为"的缺点是降低了数据完整性.
定义字符串的最大限制是一件好事,可以防止长于预期的字符串进入RDBMS,并在以后检索和解析数据库中比预期更长(更多字节)的值时导致缓冲区溢出或异常/错误.
例如,如果您有一个字段接受国家/地区缩写的双字符字符串,那么您无法想象您的用户(在此上下文中是程序员)输入完整的国家/地区名称.由于您不希望它们进入"安提瓜和巴布达"(AG)或"赫德岛和麦当劳群岛"(HM),因此您不允许它们进入数据库层.此外,一些程序员可能还没有RTFMed设计文档(肯定存在)知道不这样做.
将字段设置为接受两个字符并让RDBMS处理它(通过截断或通过拒绝它们的SQL而错误地解析).
无理由超过一定长度的实际数据示例:
加拿大邮政编码的格式为A1A1A1,长度始终为6个字符,即使对于圣诞老人也是如此(6个字符不包括可识别的易读性空间).
电子邮件地址 - @之前最多64个字节,之后最多255个字节.永远不要更多,以免你打破互联网.
北美电话号码不超过10位数(不包括国家/地区代码).
运行的计算机(最新版本)Windows的计算机名称不能超过63个字节,但不建议使用超过15 个,并且会破坏Windows NT服务器场.
州缩写是2个字符(如上面的国家代码所示)
UPS跟踪号码长度为18,12,11或9个字符.18个字符的数字以"1Z"开头,11个字符的数字以"T"开头,这让您想知道如果他们不知道字母和数字之间的差异,他们如何提供所有这些包.
等等...
花点时间考虑一下您的数据及其限制.毕竟,如果你是建筑师,开发人员或程序员,那就是你的工作.
通过使用varchar(n)而不是varchar(255),您可以消除用户(最终用户,程序员,其他程序)意外输入长时间数据的问题,这些数据将在稍后回来困扰您的代码.
我并没有说你不应该在你的应用程序使用的业务逻辑代码中实现这个限制.
我和你在一起.对细节的挑剔注意是颈部疼痛,价值有限.
曾几何时,磁盘是一种宝贵的商品,我们过去常常用子弹来优化磁盘.存储价格下降了1000倍,使得压缩每个字节的时间变得不那么有价值了.
如果仅使用CHAR字段,则可以获得固定长度的行.如果您为字段选择了准确的大小,这可以节省一些磁盘实际重新设置.您可能会获得更密集的数据(用于表扫描的I/O更少)和更快的更新(更容易在块中查找开放空间以进行更新和插入.)
但是,如果您高估了您的尺寸,或者您的实际数据大小是可变的,那么您最终会在CHAR字段中浪费空间.数据封装的密度较小(导致大量检索的I/O更多).
通常,尝试在可变字段上放置大小的性能优势很小.与CHAR(x)相比,您可以使用VARCHAR(255)轻松进行基准测试,看看是否可以测量差异.
但是,有时,我需要提供"小","中","大"的提示.所以我使用16,64和255作为尺寸.
如今,我无法想象它真的重要了.
使用可变长度字段会产生计算开销,但是由于今天的CPU过多,它甚至不值得考虑.I/O系统非常慢,以至于无法有效地处理varchars的任何计算成本.事实上,varchar的价格在计算上可能是通过在固定长度字段上使用可变长度字段而节省的磁盘空间量的净胜利.您最有可能拥有更大的行密度.
现在,varchar字段的复杂性在于您无法通过它的记录号轻松找到记录.当您具有固定长度的行大小(具有固定长度字段)时,计算行id指向的磁盘块是微不足道的.使用可变长度行大小,这种情况会从窗口中消失.
因此,现在您需要维护某种记录号索引,就像任何其他主键一样,或者您需要制作一个强大的行标识符,用于对标识符中的详细信息(例如块等)进行编码.但是,如果这样做,则必须重新计算id,如果行在持久存储上移动的话.没什么大不了的,只需要重写所有的索引条目并确保你要么a)永远不要将它暴露给消费者,要么b)从不断言这个数字是可靠的.
但是由于我们今天有varchar字段,varchar(16)与varchar(255)的唯一值是DB将对varchar(16)强制执行16个字符串限制.如果假设DB模型实际上代表物理数据模型,则具有字段长度可以是有价值的.然而,如果它只是"存储"而不是"模型和存储",那么就没有必要了.
然后,您只需要在可索引的文本字段(例如varchar)与不可记录的文本字段(如文本或CLOB字段)之间进行区分.可索引字段往往对大小有限制以便于索引,而CLOB字段则没有(在合理范围内).
根据我的经验,如果你允许一个255个字符的数据类型,一些愚蠢的用户(或一些有经验的测试人员)实际上会填补它.
然后,您会遇到各种各样的问题,包括您在应用程序中的报告和屏幕显示中允许的空间大小.更不用说超出数据库中数据的每行限制的可能性(如果你有超过255个字符字段中的一些).
在开始时更容易选择合理的限制,然后通过应用程序和数据库强制执行.