在每个数据库引擎中存储二进制标志/布尔值的最佳方法是什么?

时间:2010-12-26 22:41:31

标签: database-design flags bitflags

我见过一些可能的方法(在某些数据库引擎中有些是同义词):

  1. TINYINT(1)
  2. BOOL
  3. 位(1)
  4. ENUM(0,1)
  5. CHAR(0)NULL
  6. 应该注意PHP支持的所有主要数据库引擎,但作为参考,如果还注意到其他引擎,它会更好。

    我要求的设计最适合阅读。 例如使用WHERE条件中的flag字段或GROUP BY标志进行选择。 性能比存储空间重要得多(除非大小对性能有影响)。

    还有一些细节:

    在创建表时,我不知道它是否稀疏(如果大多数标志打开或关闭),但我可以稍后更改表,所以如果有什么我可以优化,如果我知道,应该指出。

    另外,如果每行只有一个标志(或几个),那么与许多(或很多)标志相比,它会有所不同。

    顺便说一下,我在以下的某处阅读过:

      

    使用布尔值可以做同样的事情   使用tinyint,但它有   语义传达的优点   你的意图是什么,那就是   值得的。

    嗯,在我的情况下它并不值得,因为每个表都由我的应用程序中的一个类表示,所有内容都在类中明确定义并且有详细记录。

3 个答案:

答案 0 :(得分:6)

这个答案适用于ISO / IEC / ANSI标准SQL,包括更好的免费软件假装-SQL。

第一个问题是你已经确定了两个类别,而不是一个,所以无法对它们进行合理的比较。

一个。第一类

(1)(4)和(5)包含多个可能的值并且是一个类别。所有这些都可以在WHERE子句中轻松有效地使用。它们具有相同的存储空间,因此存储和读取性能都不是问题。因此,剩下的选择只是基于列的实际数据类型。

ENUM是非标准的;更好或标准的方法是使用查找表;然后,值在表中可见,而不是隐藏,并且可以由任何报表工具枚举。由于内部处理,ENUM的读取性能将受到轻微影响。

B中。第二类

(2)和(3)是两值元素:真/假;男/女;死/活着。该类别与第一类不同。它在您的数据模型和每个平台中的处理方式都不同。 BOOLEAN只是BIT的同义词,它们是同一个东西。合法(SQL-wise)所有符合SQL的平台都处理相同的问题,并且在WHERE子句中使用它没有问题。

性能的差异取决于平台。 Sybase和DB2将最多8个BIT打包成一个字节(这里的存储不重要),并动态映射二次幂,因此性能非常好。 Oracle在每个版本中都做了不同的事情,我看到建模者使用CHAR(1)而不是BIT来克服性能问题。 MS在2005年之前很好,但他们已经打破了2008年,因为结果是不可预测的;所以简短的回答可能是将其实现为CHAR(1)。

当然,假设你不会把一些愚蠢的东西,例如包装8个单独的列放到一个TINYINT中。这不仅是一个严重的规范化错误,对编码员来说也是一场噩梦。保持每列不连续且具有正确的数据类型。

℃。多指标&可空栏目

这与(A)和(B)无关,独立于(A)和(B)。列正确的数据类型是什么,与您拥有的数量以及它是否为Nullable是分开的。 Nullable意味着(通常)该列是可选的。基本上你还没有完成建模或规范化练习。功能依赖性是模糊的。如果完成规范​​化练习,则不会有Nullable列,也不会有可选列;要么它们显然存在于特定关系中,要么它们不存在。这意味着使用Supertype-Subtypes的普通Relational结构。

当然,这意味着更多的表,但没有空。 Enterpise DBMS对于更多表或更多联接没有问题,这是他们优化的。规范化数据库比非规范化数据库或非规范化数据库执行得更好,并且可以在不“重新分解”的情况下扩展它们。您可以通过为每个子类型提供视图来简化使用。

如果您想了解有关此主题的更多信息,请查看此question/answer。如果您需要建模方面的帮助,请提出一个新问题。在你的质疑水平上,我会建议你坚持使用5NF。

d。无效表现

另外,如果性能对您很重要,则排除Null。每个Nullable列都存储为可变长度;这需要对每个行/列进行额外处理。企业数据库对这些行使用“延迟”处理,以允许日志记录等移动思想队列而不妨碍固定行。特别是从不在索引中使用可变长度列(包括Nullable列):需要在每次访问上解压缩。

电子。轮询

最后,我不认为这个问题的重点是民意调查。很公平,你会得到技术答案,甚至意见,但民意调查是针对人气竞赛,SO的响应者的技术能力涵盖范围很广,所以最流行的答案和技术上最正确的答案是两个不同的结束了。

答案 1 :(得分:1)

我知道这不是你想要的答案,但除了最极端的特殊情况之外,差异实际上是疏忽的。在每种这样的特定情况下,简单地切换数据类型将不足以解决性能问题。

例如,以下是一些替代方案,它们的性能优于任何数据类型。当然,每个都带有它的缺点。

如果你有200个可选标志,并且每次最多查询1-2个行,那么通过在每个表中放置每个标志可以获得更好的性能。如果数据真的很稀疏,那就更好了。

如果您有200个强制标记,并且只执行单个记录提取,则应将它们放在同一个表中。

如果你有一小组标志,你可以使用位掩码将它们打包在一列中,这是有效的存储方式,但是你将无法(轻松地)查询单个标志。当然,当flags可以为NULL时,这不起作用......

或者你可以发挥创意并使用“垃圾维度”概念,在其中创建一个单独的表,其中所有200个布尔标志表示为列。为每个不同的标志值组合创建一行。每行都会获得一个自动增量主键,您可以在主记录中引用该主键。哇拉,主表现在包含1个int而不是200个 列。黑客天堂,DBA的噩梦。

我想说的是,尽管争论哪个是“最好的”是有趣的,但还有其他一些更重要的问题(比如你引用的评论)。仅仅因为当您遇到真正的性能问题时,数据类型既不是问题也不是解决方案。

答案 2 :(得分:0)

以上任何一种情况都可以,我个人倾向于使用BOOL,如果它得到适当的支持,因为这最能传达你的意图,但我会避免使用ENUM(0,1)

ENUM的第一个问题是它要求其值为字符串。 01看起来像一个数字,所以程序员倾向于向它发送一个数字。

ENUM的第二个问题是,如果你发送一个错误的值,它默认为第一个枚举,在某些数据库中,它甚至不会指示错误(我正在看你的MySQL)。这使得第一个问题更加严重,因为如果您不小心发送它1而不是"1",它将存储值"0" - 非常违反直觉!

我认为这不会影响所有数据库引擎(不知道,还没有尝试过所有这些引擎),但是它影响了我们认为足够多的数据引擎,我认为这样做是不错的。