2009-12-26 207 views
90

我有一个MySQL表,其中的行是动态插入的。因为我不能确定字符串的长度并且不希望它们被截断,所以我使它们的varchar(200)通常比我需要的大得多。在给varchar字段的长度超过必要时,是否会有大的性能下降?MySQL表中varchar长度的重要性

回答

60

不,从某种意义上说,如果您在该列中存储的值总是(比如说)少于50个字符,则声明该列为varchar(50)varchar(200)具有相同的性能。

+4

不完全如此。查看[Bill Karwin]的答案(http://stackoverflow.com/questions/1962310/importance-of-varchar-length-in-mysql-table#answer-1962329) – hejdav 2016-10-05 09:17:37

+0

我认为类似的答案应该由docs支持,基准或类似的东西。 – 2018-01-07 12:40:39

13

VARCHAR非常适合你所描述的情况,因为它的全称是“可变字符” - 限制,根据你的榜样,是200个字符,但东西少被接受将无法​​填补的分配大小该列。

VARCHAR也占用较少的空间 - 值存储为单字节或双字节长度前缀加数据。长度前缀表示该值中的字节数。如果值不超过255个字节,则列使用一个长度字节,如果值可能需要超过255个字节,则使用两个长度字节。

有关将MySQL CHAR与VARCHAR数据类型进行比较的更多信息,请参见this link

+1

MySQL存储(关于CHAR和VARCHAR)中的每个人都应该阅读本答案中提到的链接。谢谢! – Pascal 2016-02-25 09:21:52

3

表现?没有。磁盘存储?是的,但价格便宜而丰富。除非你的数据库会增长到TB级,否则你可能没问题。

+0

奇怪的是,这个答案在发布六年后被低估了,其他的都没有。似乎斗气和小气。这个答案没有任何不正确的地方。版主? – duffymo 2016-04-06 23:04:05

+0

这里有一个upvote – 2017-09-22 09:04:33

+0

正如它所说,它确实影响性能。另外,磁盘存储也不是免费的。更宽的列意味着更多的磁盘读取/写入(并且磁盘访问是懒惰的),还有更宽的索引,这降低了它们的有用性。这两件事都会对性能产生负面影也许这对于一个小型数据库来说可以忽略不计,但正如你所说,在千兆字节/兆字节的规模上它肯定会很重要。对于100个注册表而言,这并不重要。 – Alejandro 2017-12-27 13:24:27

0

作为varchar而不是char,大小是基于一个内部字段来表示它的实际长度和字符串本身。因此,使用varchar(200)与使用varchar(150)并无太大区别,除了您有可能更多地存储 。

而且你应该考虑一个行增长时更新会发生什么。但是,如果这很罕见,那么你应该没问题。

241

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

+25

+1。我还看到一些JDBC驱动程序在设置缓冲区以检索行时为最大大小分配足够的空间。不用说,当一些小丑刚刚完成varchar(50000)以防万一某人有一个非常大的姓氏时,这会引起很多焦虑和咬牙切齿:-) – paxdiablo 2009-12-26 01:03:34

+15

+1。这是一个重要的影响,我相信这是这个问题的真正答案。 – 2010-02-14 08:07:52

+6

这个答案和接受的答案都是理解OP的正确答案所必需的。 – kd8azz 2013-02-19 23:37:27

1

可以有性能点击 - 但通常不在大多数用户会注意的级别。

当预先知道每个字段的大小时,MySQL确切知道每个字段/行之间有多少字节,并且可以在不读取所有数据的情况下向前翻页。使用可变字符减少了优化的能力。

Does varchar result in performance hit due to data fragmentation?

更妙的是,char vs varchar

对于大多数用途,你会没事的 - 但有的区别,对于大型数据库,你有选择其中一个的原因。

10

尺寸是性能!尺寸越小越好。不是今天或明天,但总有一天,无论您设计了什么样的设计,在严重的瓶颈问题上,桌子都会变大。但是,您可以预见设计阶段中可能首先发生的一些潜在瓶颈,并尝试扩展数据库快速且快乐地执行的时间,直到您需要重新考虑计划或通过添加更多服务器进行水平扩展。

在您的情况下,您可能遇到很多性能泄漏:对于长的varchar列,大连接几乎不可能。索引这些列是真正的杀手。您的磁盘必须存储数据。一个内存页面可以容纳较少的行,并且表扫描速度会更慢。查询缓存也不太可能在这里帮助你。

你必须问自己:每年可能会发生多少次插入?平均长度是多少?我是否真的需要超过200个字符,或者我是否可以在应用程序前端捕获这些字符,甚至可以通知用户最大长度?我是否可以将表格分成狭义的表格进行快速索引和扫描,以及另一个表格是否容纳扩展大小的额外的,不太常用的数据?我可以将可能的varchar数据输入到类别中,然后将一些数据提取到几个较小的,也许是int或bool-类型的列中,并以这种方式缩小varchar列吗?

你可以在这里做很多事情。最好先进行第一个假设,然后使用实际测量的性能数据逐步重新设计。祝你好运。

+0

+1用于列出设计选项并探索影响。对我的问题也很有帮助。 http://stackoverflow.com/q/12083089/181638 – 2012-08-24 06:39:04

+4

设置较高的最大长度是否会对实际性能产生影响,还是由实际大小决定的性能? – poolie 2013-06-14 04:03:27

3

你们有些人误以为varchar(200)占用磁盘上的表格大小比varchar(20)多。不是这种情况。只有超过255个字符时,mysql才会使用额外的字节来确定varchar字段数据的长度。

+8

临时表和“MEMORY”表不是这样。 – 2011-09-11 18:12:17

+3

任何时候,您的选择查询使用临时表(组和按操作顺序等),它会将varchar(200)转换为char(200),并且性能将受到影响。 – Jamie 2013-02-07 20:14:35

0

根据数据类型名称表明这是VARCHAR即变量字符数据存储,mysql引擎本身根据存储的数据分配正在使用的内存,所以根据我的知识没有性能影响。

0

您应该尝试在大多数场景中查看与char列相同的varchar列,并保守地设置长度。你不必总是将var修饰语想象成影响你在最大长度上作出决定的东西。它应该被看作是一种表现提示,而不是提供的字符串会有不同的长度。

这不是一个必须严格遵循数据库内部指令的指令,它可以完全忽略。不过要注意这一点,因为有时候实现可能会泄漏(例如固定长度和填充),即使它不应该处于理想的世界。

如果你有一个varchar(255),那么你不能保证性能明智,它总是会在所有情况下对char(255)的行为有不同的表现。

将内容设置为诸如255,65535等内容似乎很容易与内存需求手册中给出的建议内嵌。这给人的印象是,0(是的,这是一件事)和255之间的任何值都会产生相同的影响。但是,这并不能完全保证。

在行存储方面,存储需求往往是真实的或者是体面和成熟的持久存储引擎的良好指标。它并不像指数那样强大。

有时候这是一个很难的问题,一个字符串的长度应该设置多长时间才能达到您应该知道的最高界限,但这并没有影响。不幸的是,这通常是留给用户去解决的,它确实有点武断。你不能说永远不要超过一个字符串,因为有些情况下你不确定。

当字符串过长而不是截断时,您应该确保MySQL查询抛出错误,以便至少知道它是否可能与错误排放过短。调整列的大小以放大或缩小列可能是昂贵的DDL操作,应该牢记这一点。

字符集也应该考虑长度和性能的起作用。长度是指这个而不是字节。例如,如果使用utf8(不是MB4),则varchar(255)确实是varbinary(3 * 255)。如果没有运行测试并深入研究源代码/文档,很难知道如何实现这些功能。由于这个原因,可能会出现意想不到的膨胀影响。这不仅适用于表演。如果你有一天需要将varchar列的字符集更改为更大的字符集,那么如果允许不必要的长字符串出现,可能会避免,最终可能会遇到一些无法追索的限制。这通常是一个相当小的问题,但它确实出现了,最近引入了用于MySQL的utf8mb4和对密钥长度有限制的索引是一个重大问题。

如果事实证明MAX(LENGTH(column))总是为< 64(例如,如果确定输入的限制与列定义不匹配),但是您有varchar(255 )那么在某些情况下,您很可能会使用比所需空间多四倍的空间。

这可能包括:

  • 不同的引擎,有些人可能会完全忽略它。
  • 缓冲区大小,例如更新或插入可能必须分配完整的255(虽然我没有检查源代码来证明这一点,它只是一个假设)。
  • 索引,如果您尝试从大量varchar(255)列创建组合键,这将立即显而易见。
  • 中间表和可能的结果集。考虑到事务的工作方式,有些东西可能并不总是可能使用列中字符串的实际最大长度,而不是定义的限制。
  • 内部预测优化可能会将最大长度作为输入。
  • 数据库实施版本的变化。

作为一个经验法则,实际上没有必要使varchar比它需要的时间更长,性能问题或不是,所以我建议尽量坚持。花更多的努力来抽样数据的大小,通过询问/研究来强制实际限制或找出真正的限制是理想的方法。

如果你不能,如果你想对varchar(255)做些什么,如果有疑问的话,那么我建议你去做科学。这可能包括复制表格,减少var char列的大小,然后将数据从原始数据复制到其中,并查看索引/行数据的大小(索引列也可以将其作为主键在InnoDB中行的行为可能与行按主键排序的行为不同)。至少通过这种方式,您将知道您是否对IO有影响,而这往往是最敏感的瓶颈之一。测试内存使用情况比较困难,很难对其进行详尽的测试。我会建议测试潜在的最坏情况(在内存结果中有很多中间值的查询,检查大临时表的解释等)。

如果你知道表中不会有很多行,你不会使用连接列,索引(特别是复合,唯一)等等,那么你很可能不会有很多问题。