通常,我总是使用Ints。我知道,从理论上讲,这不是最佳实践,因为您应该使用能够保证存储数据的最小数据类型。例如,最好在知道时使用tinyint您将存储的唯一数据是1、0或null(极有可能在以后将其扩展为2或3)。

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

仅在tinyint上使用smallint(或bigint甚至int)会有什么影响,除了节省硬盘空间外?

评论

这是一个非常好的问题(+1)。 MySQL具有SELECT ... PROCEDURE ANALYSE(),实际上建议表对于给定的SELECT应该具有的最小数据类型。这部分是我回答背后的灵感。

很好的问题,但精确地说,tinyint范围是0-255。位字段是0或1(或NULL)。 tinyint的存储成本为1个字节。表中的每8位字段将花费1字节的存储空间。 msdn.microsoft.com/en-us/library/ms187745.aspx和msdn.microsoft.com/en-us/library/ms177603.aspx

@billinkc对。这就是为什么我提到有可能将列扩展为包含值2或3。如果包含2或3,则必须使用tinyint(以最小的比例)。

“例如,当您知道将要存储的唯一数据是1、0或null(极有可能将其扩展到2或3)时,最好使用tinyint。”我会用ENUM这样的东西。这些存储为位域,正如许多其他人在这里指出的那样,每条记录的少量节省总计将构成整个数据库的大量节省-如果对列进行索引,则更是如此。

@ user6665我会使用ENUM这样的东西。不在SQL Server中,您不会,因为它没有任何类型的枚举。

#1 楼

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

不要再考虑存储空间,而要考虑缓冲池和存储带宽。在最末端,CPU缓存和内存总线带宽。链接的文章是该系列文章的一部分,着重介绍了群集键选择不佳的问题(INT vs GUID vs Sequential GUID),但突出了字节可以产生的差异。

首要信息是设计问题。直到您到达VLDB区域,差异才会显示在具有适当规格的服务器上的单个数据库中,但是如果可以保存一些字节,为什么不这样做。

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

#2 楼

除了其他答案以外,

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

nvarchar到varchar的情况相同,smalldatetime到日期时间,将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字节)。

– Mark Storey-Smith
11年8月23日在19:28

我曾经在int vs bigint上进行过性能测试。保存一百万条记录,比较时间和存储,然后一个接一个地检索它们,再次衡量性能。我没有发现主要差异。我将对int vs tinyint做相同的性能测试。我真的认为80%的应用程序都可以忽略它,从而导致更一致的数据类型和更少的维护成本。

– Saeed Neamati
16年1月12日在7:03

@SaeedNeamati您可能想重新阅读Mark的回答中的文章(“您听过吗……让我们做完这件事–我们会担心性能吗?……我一直都在听……”),gbn在这里。我认为要领会的是,任何低效的选择都将以适当的比例显示其条纹,OP的直觉也没有错。

–松饼
17年11月9日15:22



#3 楼

不仅要考虑表存储。如果使用int列是复合键一部分的索引,则自然会希望索引页尽可能完整,这是由于索引项要尽可能小。

我会肯定希望发现使用较小的数据类型来检查BTREE页面中的索引条目会更快一些。但是,索引条目中涉及的任何VARCHAR都会抵消(无效化)使用TIN上的TINYINT所带来的性能提升。

尽管索引条目具有复合条目并且全部是整数,但整数沿字节方向较小,则更好,更快。

#4 楼

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


维护窗口需要扩大或重新安排
备份(一天结束时的完整备份成为荒唐的耗时者,因此
您需要差异备份或什至日志备份,并进行完整的
每周一次,也许每月一次)
性能维护变得很费时(创建索引)在数百万行的表上花费很少的时间来执行),并且需要重新安排时间,如果表很宽会变得更糟...
通过网络传输100Gb备份并不是我所说的的麻烦-特别是如果网络(由于某些未知原因)在断开75Gb标记上的连接时固执...(发生在我正在备份到网络上映射驱动器的安装中-网络)...

与此相关的数据类型是什么?一切。如果使用的行大小大于必需的行数,则数据库页面将比需要的空间更早填充,或者如果行的大小使得该页面上最多可以记录一条记录,则浪费空间。结果是需要写入和读取更多的页面,更多的RAM内存用于缓存(更大的记录需要更大的内存)。而且,由于指定的数据类型大于磁盘所需的数据类型,因此索引将遭受相同的问题-特别是如果您将2个BIGINT列的主键群集在一起,因为创建的任何其他索引都会在其定义上隐式复制该主键。

如果您知道某个表中的某些列将具有数百万行,甚至有一个小表可以将FK扩展为数百万行,而无需存储4个字节的整数他们的数据,但是2字节就足够了-使用SMALLINT。如果范围在0-255之间的值足够,请使用TINYINT。是/否标志?有BIT。

#5 楼

尽管tinyintint之间存在明显的差异,例如磁盘空间,页面拆分和维护时间,但varchar却没有任何区别。

所以为什么不将所有文本字段都声明为varchar(4000),因为无论如何,它只会占用所需的空间吗?甚至可以保证您的数据永远不会被截断。

当然,答案是:


明确您的意图(因为没人会理解为什么)名称字段应为4000个字符)
要进行验证,以确保没有人输入完整的传记作为名称。

这些原因也适用于tinyint

评论


这是一个较旧的线程,但是澄清和验证不是唯一的原因。如果您将VARCHAR(4000)设置为应为VARCHAR(20),则查询计划将认为您的内存和CPU要求是该列应为的许多倍。我没有花时间去做,但是我猜测您可能可以通过查看VARCHAR(20)的查询计划然后更改为VARCHAR(4000)并检查估计的成本来看到这一点。

–user41646
14年6月25日在16:39

@GeorgeShouse在这里的演示

–马丁·史密斯
2014年6月25日在21:07

同样,varchar≤255使用较少的行空间。

–PRMan
7月27日18:27