mysql - SQL varchar 列长度的最佳实践

标签 mysql sql sql-server postgresql

每次设置一个新的 SQL 表或向现有表添加一个新的 varchar 列时,我都想知道一件事:length 的最佳值是多少>。

因此,假设您有一个名为 name 的列,类型为 varchar。所以,你必须选择长度。我想不出一个> 20个字符的名字,但你永远不会知道。但我总是四舍五入到下一个 2^n 数字,而不是使用 20。在这种情况下,我会选择 32 作为长度。我这样做是因为从计算机科学家的角度来看,数字 2^n 在我看来比其他数字更 even,我只是假设下面的架构可以处理这些数字略好于其他人。

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

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

最佳答案

据我所知,没有任何 DBMS 有任何“优化”可以使 2^n 长度的 VARCHARmax 执行得更好code> 长度不是 2 的幂。

我认为早期的 SQL Server 版本实际上对长度为 255 的 VARCHAR 的处理与最大长度更大的不同。我不知道现在是否仍然如此。

对于几乎所有 DBMS,所需的实际存储空间仅取决于您放入其中的字符数,而不是您定义的 max 长度。因此,从存储的角度来看(很可能也是性能方面),将列声明为 VARCHAR(100)VARCHAR(500)< 没有任何区别

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

对于 PostgreSQL,最好的设置是使用没有长度限制的 text 和一个 CHECK CONSTRAINT,它将字符数限制为您的业务需要的任何内容。

如果该要求发生变化,更改检查约束比更改表要快得多(因为不需要重写表)

这同样适用于 Oracle 和其他 - 在 Oracle 中,它会是 VARCHAR(4000) 而不是 text

我不知道 VARCHAR(max) 和 e.g. 之间是否存在物理存储差异。 SQL Server 中的 VARCHAR(500)。但显然,与 varchar(8000) 相比,使用 varchar(max) 会对性能产生影响。

this link (由 Erwin Brandstetter 作为评论发表)

编辑 2013-09-22

关于bigown的评论:

在 9.2 之前的 Postgres 版本中(在我编写初始答案时不可用),对列定义的更改 确实 重写了整个表,请参见例如here .从 9.2 开始,情况不再如此,一项快速测试证实,增加具有 120 万行的表的列大小确实只需要 0.5 秒。

对于 Oracle 来说,这似乎也是正确的,从更改大表的 varchar 列所需的时间来看。但我找不到任何引用。

对于 MySQL the manual says在大多数情况下,ALTER TABLE 会制作原始表的临时副本”。我自己的测试证实:在有 120 万行的表上运行 ALTER TABLE(与我使用 Postgres 的测试相同)以增加列的大小需要 1.5 分钟。但是,在 MySQL 中,您可以使用“解决方法”来使用检查约束来限制列中的字符数。

对于 SQL Server,我找不到明确的说明,但增加 varchar 列(同样是上面的 120 万行表)大小的执行时间表明 重写发生。

编辑 2017-01-24

似乎我(至少部分)对 SQL Server 有误。见 this answer from Aaron Bertrand这表明 nvarcharvarchar 列的声明长度会对性能产生巨大影响。

关于mysql - SQL varchar 列长度的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8295131/

相关文章:

sql-server - SQL : Group by one column, 计算所有行并根据 row_number 保留第二列的值

mysql - MAMP mysql 问题

c# - 如何通过主键获取大量数据库表记录?

php - 更新sql查询不会通过php中的mysqli_query()更新记录

sql 行数条件并集

sql-server - 使用 FireDac 在 Delphi 中动态创建和调用存储过程的正确方法是什么?

c# - 如何使用自动增量列 SQLite 插入行

具有多个左外连接的 Mysql 案例

java - Apache Derby 为我创建的具有有意义名称的索引提供了奇怪的名称

sql - SQL UPDATE 操作是否将数据读取到 "local memory"?