何时使用 TINYINT 而不是 INT?

Ric*_*ard 93 sql-server database-theory

一般来说,我总是使用 Ints。我知道理论上这不是最佳实践,因为您应该使用保证存储数据的最小数据类型。

例如,tinyint当您知道将存储的唯一数据是 1、0 或 null(以后将其扩展为 2 或 3 的可能性很小)时,最好使用。

但是,我知道这样做的唯一原因是出于存储目的——在一行中使用 1 个字节而不是 4 个字节。

除了节省硬盘空间之外,仅使用tinyintsmallint甚至bigint)会产生什么影响int

Mar*_*ith 97

磁盘空间很便宜……这不是重点!

停止考虑存储空间,而是考虑缓冲池和存储带宽。在极端情况下,CPU 缓存和内存总线带宽。链接的文章是该系列的一部分,重点介绍了集群键选择不佳的问题(INT vs GUID vs Sequential GUID),但它强调了字节可以产生的差异。

最重要的信息是设计问题。在您到达 VLDB 领域之前,差异不会出现在适当规范的服务器上的单个数据库中,但如果您可以节省几个字节,为什么不这样做。

我想起了之前一个问题中描述的环境。每个 SQL 实例 400 多个数据库,大小从 50mb-50GB 不等。在该环境中清理每个记录、每个表、每个数据库的几个字节可能会产生重大影响。


gbn*_*gbn 30

除了其他答案...

行和索引条目存储在 8k 页中。因此,每行 3 字节的 100 万行不是磁盘上的 3 MB:它会影响每页的行数(“页密度”)。

这同样适用于 nvarchar 到 varchar、smalldatetime 到 datetime、int 到 tinyint 等

编辑,2013 年 6 月

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

这篇文章指出

重要的标准是基数和页行比。

所以,数据类型的选择很重要

  • 好点子。一个绝对最坏的例子是一个 4028 字节的行,由你想要添加一列的完全固定长度的列组成。添加 smallint 将带您到 4030(每页 2 行),但 int 会将您推到边界(每页 1 行,每页浪费 4028 字节)。 (5认同)

Rol*_*DBA 14

不仅仅是表存储是一个考虑因素。如果在 int 列是复合键的一部分的情况下使用索引,您自然希望索引页尽可能满,这是索引条目尽可能小的结果。

我肯定会发现使用较小的数据类型检查 BTREE 页面中的索引条目会更快一些。但是,索引条目中涉及的任何 VARCHAR 都会抵消(抵消)使用 TINYINT 而不是 INT 的性能提升。

尽管如此,如果索引条目有复合条目并且都是整数,那么字节的整数越小越好,速度也越快。


Fab*_*ujo 13

当数据库变大时,所有事情都会变得复杂:

  • 需要扩大或重新安排维护窗口
  • 备份(一天结束的完整备份变成了一个荒谬的时间吞噬者,所以你需要一个差异备份甚至是日志备份,并且每周做一次完整的备份,也许一个月一次)
  • 性能维护变得耗时(在数百万行的表上创建索引需要花费大量时间来执行)并且需要重新安排并且如果表很宽会变得更糟......
  • 通过网络传输 100Gb 备份并不是我所说的小菜一碟——特别是如果网络(出于某种未知原因)在断开 75Gb 标记上的连接时很顽固......(发生在我正在工作的安装中)正在备份到网络上的映射驱动器)...

什么数据类型与此有关?一切。使用大于必要的行大小会使数据库页面比所需的填充时间提前,如果行大小使得页面上不能记录超过一条记录,则甚至会浪费空间。结果是需要写入和读取更多页面,使用更多 RAM 内存来缓存(更大的记录需要更多内存)。并且由于您指定的数据类型大于磁盘所需的数据类型,因此您的索引将遇到同样的问题 - 特别是如果您对复合 2 BIGINT 列主键进行聚类,因为创建的任何其他索引都会在其定义中隐式复制该主键。

如果您知道表中的某些列将有数百万行,甚至是一个小表,该表将 FK 转换为不需要 4 字节整数来存储其数据的数百万行,但 2 字节将就足够了 - 使用SMALLINT。如果 0-255 范围内的值就足够了,则TINYINT。是/否标志?有比特


小智 9

虽然对于tinyintvsint存在明显的差异,例如磁盘空间、页面拆分和维护时间,但对于varchar.

那么为什么不将所有文本字段声明为varchar(4000),因为它只会占用所需的空间?更重要的是,您将保证您的数据永远不会被截断。

答案当然是:

  1. 澄清您的意图(因为没有人会理解为什么名称字段应该是 4000 个字符)
  2. 验证,因为你想确保没有人输入整个传记作为名字。

这些非常相同的原因也适用于tinyint

  • 这是一个较旧的线程,但澄清和验证不是唯一的原因。如果你有 VARCHAR(4000) 应该是 VARCHAR(20) 的东西,查询计划会认为你的内存和 CPU 需求是它们应该是关于该列的很多倍。我没有花时间这样做,但我猜您可能会通过查看 VARCHAR(20) 的查询计划然后更改为 VARCHAR(4000) 并检查估计成本来看到这一点。 (3认同)
  • @GeorgeShouse [此处演示](http://stackoverflow.com/questions/2009694/is-there-an-advantage-to-varchar500-over-varchar8000/5654947#5654947) (3认同)