SQL数据类型 - 如何存储年份?

53

我需要在数据库中插入一个年份(例如:1988、1990等)。当我使用日期或时间日期数据类型时,会出现错误。我应该使用哪种数据类型?


1
这个问题肯定需要更多关于使用场景的信息,但时区往往是很重要的。1990年在澳大利亚开始的时间比在美国更早。一个简单的整数或字符串通常不是日期的正确选择。 - Sebastiaan van den Broek
8个回答

46

正常的4字节整数太大了,浪费空间!

你没有说明你使用的是哪种数据库,所以我无法推荐具体的数据类型。虽然许多人都建议使用“integer”类型,但大多数数据库将整数存储为4个字节,这远远超出了您的需求。您应该使用两个字节的整数(在SQL Server中为smallint),这将节省空间。


5
通常情况下,使用int类型浪费空间比使用更小的数据类型更可取,因为大多数现代处理器更有效地处理4字节的int类型(32位)而不是更小的数据类型。 - Ender
4
@Ender,你所做的不是真正意义上的数学计算,而更像是一种存储和查找过程。如果值越小,你就能在内存中存储更多的值,如果值越小,你就能从磁盘中读取更多的值等等。我找不到支持你观点的任何文章。http://dba.stackexchange.com/q/4968 - KM.
1
所有程序最终都会编译成机器代码,并将数字加载到寄存器中。在现代CPU架构中,所有寄存器都是32位或64位的。因此,您的RDBMS系统将必须将这些数字放入寄存器中,以进行比较,以满足查询中的条件。而在处理tiny int和small int的情况下,它必须每次进行转换,这是耗时的。您无法找到支持我的观点或您的观点的官方文章,因为通常需要在CPU和IO之间权衡,因为使用int会增加索引大小并需要更多IO。 - Ender
2
@ender,总是有取舍的,我会选择针对IO(和更小的数据类型)进行优化,因为IO通常是主要瓶颈。 - KM.
4
@Weapon X,“为什么要用4个字节来存储一年的时间?”一个char(4)占用四个字节。我的回答建议使用两个字节的整数,SQL Server上的“smallint”可以存储范围内的值:-32,768到32,767,这已经足够存储一年的时间了。你希望尽可能地节省空间,因为这样可以在每页中固定更多的数据,或者在内存中固定更多的数据和/或索引。如果我使用smallint而你使用char(4),那么你将使用两倍的空间/内存来存储同样的数据。对于数据库来处理你的“CHAR(4)”需要更长的时间和更多的努力,而我的“SMALLINT”则不会。 - KM.
显示剩余3条评论

35

如果你需要在数据库中存储一年的时间,你可以使用 Integer 数据类型(如果你只想存储年份)或者 DateTime 数据类型(这将涉及到存储一个日期,通常是 1990 年 1 月 1 日 00:00:00 的格式)。


25
不要懒惰,仅仅使用“int”类型。适当地选择数据类型,一个两个字节的整型是更好的选择。将4位数年份存储在4个字节中,比仅仅浪费磁盘空间更多的资源。对于这一列,您的系统将永远负担着使用了两倍的缓存内存,推送了两倍数量的IO数据等等。这很明显,请参阅:http://dba.stackexchange.com/q/4968 - KM.
7
但是32768年问题怎么办?(开个玩笑) - nitro2k01
1
@KM。我同意这是一个应该完成的简单优化,但是让我们不要因为不做它而过度激动。并不是每个项目都会看到任何显著的差异。 - Chuck Le Butt
2
@KM。我已经说过,“我同意这是一个应该做的简单优化”,所以我不知道你在争论什么。我碰巧在处理较小的临时系统,这些系统永远不会从这种改变中获得任何好处。我有10年的这样的系统历史记录。我们构建的系统是为临时使用(最长6个月)而设计的,即使在最坏/最好的情况下,如果数据库继续增长,这种优化对我们也不会产生任何明显的影响,至少需要再过10年。 - Chuck Le Butt

14

嘿,你可以在MySQL中使用year()数据类型,它有两位数和四位数格式可用。

注意:四位数格式允许的值范围为1901至2155年。 两位数格式允许的值范围为70至69,表示1970年至2069年之间的年份。


3
在MSSQL中存储“年份”理想情况下应该取决于您的应用程序和数据库对其的含义以及使用方式。尽管如此,这里有几个需要说明的事情。截至2012年,在MSSQL中没有“年份”数据类型。我倾向于使用SMALLINT,因为它只有2个字节(比INT要节省2个字节)。您的限制是不能拥有比32767更早的年份(截至SQL Server 2008R2)。我真的不认为SQL会成为未来一万年甚至32767年的首选数据库。您可以考虑使用INT,因为MSSQL中的Year()函数将数据类型“DATE”转换为INT。就像我说的,这取决于您从哪里获取数据以及数据的去向,但是SMALLINT应该完全可以胜任。使用INT则过度了……除非您有其他原因,例如上述原因或者代码要求以INT形式提供(例如与现有应用程序集成)。最可能的情况是SMALLINT应该完全可以胜任。

2
只是一年,没有别的吗? 为什么不使用一个简单的整数?

16
嘿!为什么你要试图把问题简化呢?那样我们会用尽所有的SO问题! - Joe Phillips
由于在某些情况下,数据会根据数据库列类型自动进行格式化,因此您最终可能会看到类似“2,001”和“-56”的年份,而不是“2001”和“公元前56年”等正确的显示方式。 - mgraham

2

如果你只需要存储年份,可以使用整数。如果在查询此列时需要进行基于日期的计算,也可以使用datetime。


0

我认为使用整数或任何整数子类型都不是一个好选择。早晚你会需要进行其他日期相关的操作。另外在2019年,让我们不要太担心空间。看看那些省下来的2个字节在2000年花费了我们多少。

我建议使用年份+0101转换成真实日期的方式。同样,如果需要存储某年某月,可以将年份+月份+01作为真实日期存储。

如果你这样做了,以后就能够正确地进行“日期方面”的操作了。


0

存储可能只是问题的一部分。这个值将如何在查询中使用?

它将与另一个日期时间数据类型进行比较,还是所有相关行也将具有数字值?

如果需求发生变化,你会如何处理?你能多快地响应将年份替换为更小的时间段的请求吗?即现在他们想按季度拆分它?

通过查找表来轻松地在日期时间查询中使用数值类型,包含诸如开始和结束日期(1/1/X至12/31/x)等内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接