Varchar 长度在 MySQL 表中的重要性

我有一个 MySQL 表,其中动态插入行。因为我不能确定字符串的长度,并且不希望它们被切断,所以我把它们设置为 varchar (200) ,它通常比我需要的大得多。如果给一个 varchar 字段提供比必要的长度更多的长度,是否会对性能造成很大的影响?

60682 次浏览

No, in the sense that if the values you're storing in that column are always (say) less than 50 characters, declaring the column as varchar(50) or varchar(200) has the same performance.

VARCHAR is ideal for the situation you describe, because it stands for "variable character" - the limit, based on your example, would be 200 characters but anything less is accepted 还有 won't fill the allotted size of the column.

VARCHAR 也占用较少的空间-值以一个字节或两个字节长度的前缀加上数据的形式存储。长度前缀指示值中的字节数。如果值不超过255字节,则列使用一个长度字节; 如果值可能需要超过255字节,则使用两个长度字节。

有关比较 MySQLCHAR 和 VARCHAR 数据类型的更多信息,请参见 这个链接

表演?没有。磁盘存储?是的,但是又便宜又多。除非您的数据库将增长到 TB 级别,否则您可能没有问题。

作为 varchar,而不仅仅是 char,其大小基于一个内部字段来指示其实际长度和字符串本身。因此,使用 varchar (200)与使用 varchar (150)没有太大区别,除了您有存储的潜力 更多。

您还应该考虑当行增长时,在更新时会发生什么。但如果这种情况很少见,那你应该没事。

There's one possible performance impact: in MySQL, temporary tables and MEMORY tables store a VARCHAR column as a fixed-length column, padded out to its maximum length. If you design VARCHAR columns much larger than the greatest size you need, you will consume more memory than you have to. This affects cache efficiency, sorting speed, etc.

性能可能会受到影响——但通常不会达到大多数用户都会注意到的水平。

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

Varchar 是否会因为数据碎片导致性能下降?

甚至更好,Char 对 Varchar

对于大多数应用来说,两者都可以,但是 有所不同,对于大型数据库来说,选择其中一个是有原因的。

Size is performance! The smaller the size, the better. Not today or tomorrow, but some day your tables will be grown to a size when it comes to serious bottlenecks, no matter what design you laid out. But you can foresee some of those potential bottlenecks in your design phase that are likely to happen first and try to expand the time your db will perform fast and happily until you need to rethink your scheme or scale horizontally by adding more servers.

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

You have to ask yourself: How many inserts per year may happen? What is the average length? Do I really need more than 200 characters or can I catch that in my application front-end, even by informing users about the maximum length? Can I split up the table into a narrow one for fast indexing and scanning and another one for holding additional, less frequently needed data of expanding size? Can I type the possible varchar data into categories and so extract some of the data into a few smaller, maybe int or bool-type columns and narrow the varchar column that way?

你可以在这里做很多事。最好先假设一下,然后利用实际测量的性能数据一步一步地重新设计。祝你好运。

有些人错误地认为 varchar(200)varchar(20)在磁盘上占用更多的表大小。事实并非如此。只有当超过255个字符时,mysql 才会使用一个额外的字节来确定 varchar字段数据的长度。

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

您应该尝试查看 varchar 列,就像在大多数情况下查看 char 列一样,并保守地设置长度。您不必总是考虑 var 修饰符,因为它会影响您对最大长度的决策。它实际上应该被看作是一个性能提示,而不是提供的字符串将具有不同的长度。

它不是必须严格遵循数据库内部指令的指令,可以完全忽略它。但是要注意这一点,因为有时候实现可能会泄漏(例如固定长度和填充) ,尽管在理想情况下它不应该泄漏。

如果您有一个 varchar (255) ,那么您就不能保证在所有情况下它的性能总是会与一个 char (255)有所不同。

It can seem easy to set it at something such as 255, 65535, etc inline with the advice given in the manual about storage requirements. This gives the impression that any value between 0 (yes, it's a thing) and 255 will have the same impact. However that's not something that can be fully guaranteed.

就行存储而言,存储需求往往是真实的,或者是体面和成熟的持久存储引擎的良好指示器。对于索引之类的东西来说,它不是一个强有力的指标。

有时候这是一个很难回答的问题,一根绳子到底应该有多长才能达到你所知道的最高界限,但这并没有影响。不幸的是,这通常是留给用户去解决的问题,而且它实际上有些武断。你不能说永远不要放大一个字符串,因为在某些情况下,你可能并不确定。

您应该确保 MySQL 查询在字符串太长时抛出一个错误,而不是截断,这样至少您可以知道它是否可能太短从错误发出。调整列的大小以放大或缩小它们可能是一种昂贵的 DDL 操作,应该记住这一点。

字符集也应该考虑在长度和性能发挥作用。长度指的是这个值,而不是字节。例如,如果使用 utf8,(而不是 MB4) ,那么 varchar (255)实际上是 varbinary (3 * 255)。如果不运行测试并深入研究源代码/文档,很难知道这样的事情会如何发展。正因为如此,长度过长会产生意想不到的膨胀影响。这不仅仅适用于性能。如果有一天您需要将 varchar 列的字符集更改为更大的字符集,那么如果您允许出现本来可以避免的无端长字符串,那么您可能最终会达到某个限制而无法追索。这通常是一个相当小的问题,但它确实出现了,这是最近一个重大的问题,引入 utf8mb4的 MySQL 和索引,有一个关键长度的限制。

If it turns out that MAX(LENGTH(column)) is always < 64 (such as if it was decided there would be a limit on input that wasn't matched by the column definition) but you have varchar(255) then there's a good chance that you'll be using four times more space than needed in some scenarios.

这可能包括:

  • 不同的引擎,有些可能完全忽略它。
  • 缓冲区大小(例如 update 或 insert)可能必须分配完整的255个缓冲区(尽管我没有检查源代码来证明这一点,但这只是一个假设)。
  • 索引,如果您试图从大量 varchar (255)列中创建一个组合键,这将立即显而易见。
  • 中间表和可能的结果集。考虑到事务的工作方式,可能并不总是可以使用列中字符串的实际最大长度,而不是使用已定义的限制。
  • Internal predictive optimisations might take the max length as an input.
  • 数据库实现版本的更改。

根据经验法则,varchar 实际上没有必要比它需要的更长,不管是否存在性能问题,所以我建议在可能的情况下坚持使用它。采取更多的努力抽样你的数据的大小,实施一个真正的限制或找出真正的限制,通过询问/研究是理想的方法。

当你不能,如果你想做一些事情,如 varchar (255)的情况下,有疑问,那么我建议做科学。这可能包括复制表,减少 var char 列的大小,然后将数据从原始数据复制到其中,并查看索引/行数据的大小(也可以索引该列,也可以尝试将其作为主键,这在 InnoDB 中可能会有不同的行为,因为行是按主键排序的)。至少通过这种方式,您将知道您是否对 IO 产生了影响,而 IO 往往是最敏感的瓶颈之一。测试内存使用情况更加困难,很难彻底测试。我建议测试潜在的最坏情况(内存结果中含有大量中间元素的查询,检查大型临时表的解释,等等)。

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