对所有基于文本的字段使用genericsvarchar(255)是否有缺点?

我有一个contacts表,其中包含postcodefirst namelast nametowncountryphone number等字段,所有这些都被定义为VARCHAR(255)即使这些字段没有接近255个字符。 (如果你想知道,这是因为Ruby on Rails迁移默认情况下将String字段映射到VARCHAR(255) ,我从来没有打算覆盖它)。

由于VARCHAR只会存储字段的实际字符数(以及字段长度),所以使用VARCHAR(16)不是VARCHAR(255)有什么明显的优势(性能或其他VARCHAR(255)

另外,这些领域大部分都有索引。 字段上的较大VARCHAR大小是否会影响索引的大小或性能?

仅供参考我正在使用MySQL 5。

在存储中, VARCHAR(255)非常聪明,只能存储给定行所需的长度,而不像CHAR(255)那样总是存储255个字符。

但是,既然你用MySQL标记了这个问题,我会提到一个特定于MySQL的提示:当行从存储引擎层被复制到SQL层时, VARCHAR字段被转换为CHAR来获得使用固定宽度行的优势。 因此,内存中的string会被填充到声明的VARCHAR的最大长度

当你的查询隐式生成一个临时表时,例如在sorting或GROUP BY ,这可以使用大量的内存。 如果您使用大量的VARCHAR(255)字段的数据不需要那么长,这可以使临时表非常大。

您可能还想知道,这种“填充”行为意味着使用utf8字符集声明的string即使对于以单字节内容存储的string(例如ascii或latin1字符),也可以填充每个字符三个字节。 同样,utf8mb4字符集会使string在内存中填充到每个字符四个字节。

所以在utf8中存储一个像“No opinion”这样的短string的VARCHAR(255)在磁盘上需要11个字节(十个低字节字符,加上一个字节的长度),但是在内存中需要765个字节,因此在临时表或sorting结果。

我已经帮助不经意间创build了1.5GB临时表的MySQL用户填满了他们的磁盘空间。 他们有很多VARCHAR(255)列,在实践中存储非常短的string。

最好根据您打算存储的数据types来定义列。 正如其他人所提到的那样,强制执行与应用程序有关的约束也是有好处的。 但是,为了避免我上面描述的内存浪费,它具有物理上的好处。

当然,很难知道最长的邮政地址是什么,这就是为什么许多人select一个比任何地址长的VARCHAR 。 255是惯例,因为它是可以用一个字节编码长度的VARCHAR的最大长度。 这也是MySQL 5.0以前的最大VARCHAR长度。

除了设置varchar的大小和性能方面的考虑(可能更重要,因为存储和处理每秒都会变得更便宜),“仅仅因为”使用varchar(255)的缺点是降低了数据的完整性

定义string的最大限制是一件好事,可以防止比期望的string长的string进入RDBMS,并在稍后从数据库检索和分析比预期更长(更多字节)的值时导致缓冲区溢出或exception/错误。

例如,如果您有一个字段接受国家缩写的两个字符的string,那么您就没有理由期待您的用户(在这种情况下,程序员)input完整的国家/地区名称。 既然你不想让他们进入“安提瓜和巴布达”(AG)或“赫德岛和麦克唐纳群岛”(HM),你就不要在数据库层面允许它。 另外,很可能有些程序员还没有RTFMed的devise文档( 肯定存在 )知道不这样做。

将字段设置为接受两个字符,然后让RDBMS处理它(通过截断或非正常地通过拒绝错误的SQL来优雅地处理它)。

没有理由超过一定长度的实际数据的例子:

  • 加拿大邮政编码的格式为A1A1A1,长度总是6个字符, 即使是圣诞老人 (6个字符不包括可清晰指定的空间)。
  • 电子邮件地址 – 在@之前多达64个字节,之后多达255个字节。 不要更多,免得你打破互联网。
  • 北美电话号码不能超过10位数字(不包括国家代码)。
  • 运行Windows(最新版本)的计算机的计算机名称不能超过63个字节 ,但build议不要超过15 个字符 ,并且会破坏Windows NT服务器场。
  • 州的缩写是2个字符(如上面的国家代码)
  • UPS跟踪号码的长度为18,12或11或9个字符。 18个字符的数字以“1Z”开头,11个字符的数字以“T”开头,这让你想知道如果他们不知道字母和数字之间的区别,他们如何提供所有这些包。

等等…

花时间考虑一下你的数据及其限制。 如果您是架构师,开发人员或程序员,那毕竟是您的工作

通过使用varchar(n)而不是varchar(255),您可以消除用户(最终用户,程序员或其他程序)意外input的长时间数据,这些数据在以后再次出现。

而且我没有说你不应该在应用程序使用的业务逻辑代码中实现这个限制。

我和你在一起。 对细节的注重是颈部疼痛,价值有限。

曾几何时,磁盘是一种珍贵的商品,我们曾经为了优化它而stream汗子弹。 存储的价格已经下降了1000倍,这使得花在压缩每个字节上的时间减less了。

如果只使用CHAR字段,则可以获得固定长度的行。 如果您为字段select了精确的大小,这可以节省一些磁盘实时重新编辑。 您可能会得到更密集的数据(表扫描更less的I / O)和更快的更新(更容易find更新和插入块中的开放空间)。

但是,如果你高估了你的大小,或者你的实际数据大小是可变的,那么你会浪费CHAR字段的空间。 数据将不再密集打包(导致更多的I / O的大回收)。

一般来说,试图把大小放在可变字段上的性能是很小的。 您可以通过使用VARCHAR(255)与CHAR(x)进行比较来轻松进行基准testing,以查看是否可以测量差异。

但有时候,我需要提供一个“小”,“中”,“大”的提示。 所以我使用16,64和255的尺寸。

现在,我无法想象它真的重要了。

使用可变长度字段有一个计算开销,但是由于CPU数量太多,所以甚至不值得考虑。 I / O系统太慢了,以至于无法有效处理变化的计算成本。 实际上,计算的varchar的价格可能是通过在固定长度字段上使用可变长度字段保存的磁盘空间量的净赢。 你很可能有更大的行密度。

现在,varchar字段的复杂性在于,您无法通过logging号轻松findlogging。 当你有一个固定长度的行长度(固定长度的字段)时,计算行ID指向的磁盘块是微不足道的。 随着可变长度的行,这种窗口出去。

因此,现在您需要维护某种logging号索引,就像任何其他主键一样,或者需要制作一个健壮的行标识符,用于对标识符中的详细信息(例如块等)进行编码。 如果你这样做,但是,如果在永久性存储上移动该行,则必须重新计算该id。 没什么大不了的,只需要重写所有的索引条目,并确保你a)从不向用户揭露它,或b)从不断言这个数字是可靠的。

但是由于我们今天有varchar字段,varchar(16)通过varchar(255)的唯一值是数据库将对varchar(16)强制执行16个字符的限制。 如果DB模型应该是实际的物理数据模型的代表,那么具有字段长度可能是有价值的。 但是,如果它只是“存储”而不是“模型和存储”,那就没有必要。

那么你只需要辨别可索引的文本字段(如varchar)与不是的东西(如文本或CLOB字段)。 可索引字段往往有一个大小的限制,以促进索引,而CLOB字段不(在合理的范围内)。

根据我的经验,如果你允许255个字符的数据types,一些愚蠢的用户(或一些有经验的testing人员)实际上会填补这一点。

那么,你有各种各样的问题,包括你的应用程序报告和屏幕显示允许多less空间。 更不用说超过数据库中每行数据限制的可能性(如果这些255个字符的字段中有多个)。

在开始时select一个合理的限制更容易,然后通过应用程序和数据库执行。

只分配一些你需要的东西是很好的做法。 电话号码永远不会这么大。

其中一个原因就是,除非你对大的条目进行validation,否则毫无疑问,有人会使用所有的条目。 那么你可能会用尽行中的空间。 我不确定MySQL限制,但8060是MS SQL中的最大行数。

更正常的默认值是50 imho,然后在需要certificate的情况下增加。