【问题标题】:Storing sex (gender) in database在数据库中存储性(性别)
【发布时间】:2011-05-09 17:16:26
【问题描述】:

我想以尽可能少的(大小/性能)成本将用户的性别存储在数据库中。

到目前为止,我想到了 3 个场景

  1. Int - 与代码中的 Enum 对齐(1 = 男,2 = 女,3 = ...)
  2. char(1) - 存储 mf 或其他单个字符标识符
  3. (布尔值) - 此选项是否有合适的字段名称?

我问的原因是因为answer 提到 chars smallerbooleans

我应该澄清一下,我使用的是 MS SQL 2008,它确实实际上具有位数据类型。

【问题讨论】:

  • FWIW,您引用的那个 SO 问题是指 .NET 如何在内存中表示这些类型。它与 SQL Server 如何表示它们没有任何关系。位 msdn.microsoft.com/en-us/library/ms177603.aspx
  • 你使用性别字段做什么?它可以只是一个字符串,所以人们可以输入他们喜欢的内容吗?试图列举对这个问题的所有可能的回答会很棘手。
  • @ThePassenger:我认为通常的选择基本上是 m/f/other,所以是的,像你建议的那样三元就可以了。您可能想要区分“其他”和“未指定”(如“我不告诉”和/或“我们尚未询问用户”)。我不知道性别流动的人想要一个带有每天可以设置的滑块的浮点值;我的猜测是,他们中的大多数人(以及其他非传统性别的人)会很乐意在几乎任何网站上选择“其他”或“未指定”。但是不,我不认为用“性”代替“性别”是个好主意。
  • @PeterCordes 我不太了解“性别流动”,在我的村子里,你要么是男人,要么是女人……要么是母牛。如果流派现在是流动的,那么为计算机的声音创造一个价值尺度似乎有点过分要求。在我的国家,我们宁愿要求性,它不那么复杂。哦,不要相信到目前为止我们还处于石器时代,嗯!我们已经发现了上帝,自上次殖民以来,我们大部分时间都是一神论者。
  • @PeterCordes :由于在当前的政治气候下要求这样的事情会给人们带来优势,让他们比其他人更有优势,只要你包含一个浮动值滑块,就会有人站出来要求一个多维度一。 “只有一个滑块?你在石器时代吗?”

标签: sql database-design


【解决方案1】:

这方面已经有一个 ISO 标准;无需发明自己的方案:

http://en.wikipedia.org/wiki/ISO_5218

根据标准,该列应称为“Sex”,而“最接近”的数据类型将是带有 CHECK 约束的 tinyint 或适当的查找表。

【讨论】:

  • 为什么“不适用”会跳到 9? 3-8 点呢?
  • 这是为了性。 OP特别要求性别。性别和性别可能具有不同的可能值,可能需要被捕获。
  • @indigochild OP 在问题标题中使用这两个词并清楚地认为它们是等效的,至少 对于他的用例 (YMMV)。我的观点很简单,这个领域存在 ISO 标准,当存在官方标准时,你永远不应该浪费时间设计自己的方案。当然,除非该标准不涵盖您的特定情况,这是完全可能的。
  • 这应该是公认的答案。它专注于数据完整性(这是〜永远)而不是优化(这是情境)。
  • 这绝对是答案。 @PeterCordes 此 ISO 用于性别(生物性)而不是性别(您所识别的)-explanation here。我想在想要存储性别的情况下(我不知道你有什么用途),只要你想存储少于 255 个性别(通过说 fe 0 = 未知/不想声明,1 = 男人,2 = 女人,3 = 男人认定为女人,等等)
【解决方案2】:

我会将此列称为“性别”。

Data Type   Bytes Taken          Number/Range of Values
------------------------------------------------
TinyINT     1                    255 (zero to 255)
INT         4            -       2,147,483,648 to 2,147,483,647
BIT         1 (2 if 9+ columns)  2 (0 and 1)
CHAR(1)     1                    26 if case insensitive, 52 otherwise

BIT 数据类型可以排除,因为它只支持两种可能的性别,这是不够的。虽然INT 支持两个以上的选项,但它需要 4 个字节——使用更小/更窄的数据类型时性能会更好。

CHAR(1)TinyINT 有优势 - 两者占用相同数量的字节,但 CHAR 提供的值数量更窄。使用CHAR(1) 将使用“m”、“f”等自然键,而不是使用被称为代理/人工键的数字数据。 CHAR(1) 也支持任何数据库,如果需要移植的话。

结论

我会使用选项 2:CHAR(1)。

附录

性别列上的索引可能没有有帮助,因为低基数列上的索引没有任何价值。这意味着,索引值的多样性不足以提供任何值。

【讨论】:

  • 任何关于性能的参考?我知道这几乎是我不应该做的微优化,但它是我好奇心的食物。
  • 谢谢@OMG Ponies,性能怎么样?在这种情况下,char 会比 bit 更昂贵吗?
  • @Marko:就像我之前说的,他们是平等的。但是索引可能没有有帮助,因为低基数列上的索引没有任何价值。这意味着,索引值的多样性不足以提供任何值。
  • 如果在 64 位平台上使用 4 字节数据类型,真的性能会好多少?只是说... ;-)
  • 我会坚持一点,因为只有两种性别。但是,OP 的最初问题仍然存在:列名是什么? “IsMale”或“IsFemale”有点奇怪……
【解决方案3】:

在医学上有四种性别:男性、女性、不确定和未知。您可能不需要全部四个,但肯定需要 1、2 和 4。为此数据类型设置默认值是不合适的。更不用说将其视为具有“is”和“isn't”状态的布尔值。

【讨论】:

  • @EJP,很有趣。你有这方面的参考吗?
  • 根据这些信息,我会选择 TinyInt 与枚举对齐(正如 Hugo 建议的那样),并至少选择 1、2 和 3(其他)。
  • @EJP,虽然你的回答可能是正确的,但它并没有说明我应该使用什么数据类型,而是 - (技术上)正确的性别是什么。
  • @Marko:我看不出这条评论的重点。您的问题没有“哪种数据类型”。我的回答消除了您的三个建议中的两个,并提供了背景推理。
  • UK National Health Service (NHS) data dictionary 定义了四个值:0 = Not Known、1 = Male、2 = Female、9 = Not Specified,它们镜像了 ISO 5218 值。注意有two types:注册时的性别(通常在出生后不久)和当前。
【解决方案4】:

Enum 字段对齐的Int(或TinyInt)将是我的方法。

首先,如果您在数据库中有一个 bit 字段,则该行仍将使用一个完整字节,因此就节省空间而言,只有当您有多个 bit 字段时才会有回报。

其次,字符串/字符对它们来说具有“神奇的价值”,无论它们在设计时看起来多么明显。更不用说,它可以让人们存储他们不一定映射到任何明显的任何值。

第三,一个数字值更容易(和更好的做法)创建一个查找表,以强制引用完整性,并且可以将 1 对 1 与枚举相关联,因此在存储值时存在奇偶性在应用程序或数据库中的内存中。

【讨论】:

    【解决方案5】:

    选项 3 是您最好的选择,但并非所有数据库引擎都有“位”类型。如果你没有一点,那么 TinyINT 将是你最好的选择。

    【讨论】:

      【解决方案6】:

      我使用 char 'f'、'm' 和 'u' 是因为我通过姓名、声音和对话推测性别,有时不知道性别。最终决定是他们的意见。

      这实际上取决于您对这个人的了解程度以及您的标准是物理形式还是个人身份。心理学家可能需要额外的选择——跨性别、跨性别、跨性别、跨性别、跨性别、雌雄同体和未定。有 9 个选项,不是由单个字符明确定义的,我可能会接受 Hugo 的小整数建议。

      【讨论】:

      • 不是主题。这不是答案。
      【解决方案7】:
      CREATE TABLE Admission (
          Rno INT PRIMARY KEY AUTO_INCREMENT,
          Name VARCHAR(25) NOT NULL,
          Gender ENUM('M','F'),
          Boolean_Valu boolean,
          Dob Date,
          Fees numeric(7,2) NOT NULL
      );
      
      
      
      
      insert into Admission (Name,Gender,Boolean_Valu,Dob,Fees)values('Raj','M',true,'1990-07-12',50000);
      insert into Admission (Name,Gender,Boolean_Valu,Dob,Fees)values('Rani','F',false,'1994-05-10',15000);
      select * from admission;
      

      enter link description here

      【讨论】:

        【解决方案8】:

        我会选择选项 3,但使用多个 NON NULLABLE 位列而不是一个。 IsMale(1=是/0=否) IsFemale(1=是/0=否)

        如果需要: IsUnknownGender(1=是/0=否) 等等……

        这使得定义易于阅读、易于扩展、易于编程、不可能使用域外的值并且不需要第二个查找表+FK 或 CHECK 约束来锁定值。

        编辑:更正,您确实需要至少一个约束来确保设置的标志有效。

        【讨论】:

        • 很高兴听到为什么我的回答被否决了?
        • 没有约束,没有什么可以阻止所有列为 1 或所有列为 0。这将是荒谬的,因此您的方案不满足您的要求之一。
        • 是的,您是对的,您确实需要一个约束来检查是否“检查”了正确数量的标志。我不认为所有的反对票都是因为这个遗漏......
        • 这是一个访问量很大的问题(请查看其他答案的点赞!),多年后您出现并添加了一个相当于一次性编码的答案,这是一种广泛教授的技术,它甚至没有你赋予它的几个具体属性。我不认为给你投票低于 0 是正确的,但我也不感到惊讶。
        猜你喜欢
        • 2023-04-01
        • 2017-02-07
        • 2020-03-17
        • 1970-01-01
        • 2015-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多