6

我已经看到了一些可能的方法(在一些数据库引擎中,其中一些是同义词):

  1. 小灵通(1)
  2. 布尔值
  3. 比特(1)
  4. 枚举(0,1)
  5. CHAR(0) 空

PHP支持的所有主要数据库引擎都应该注明,但作为参考,如果其他引擎也能注明,那就更好了。

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

还有更多细节:

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

此外,如果每行只有一个(或几个)标志,而不是许多(或很多)标志,则应该注意。

顺便说一句,我在某处读过以下内容:

使用 boolean 可能与使用 tinyint 做同样的事情,但是它具有在语义上传达您的意图的优势,这是值得的。

好吧,在我的情况下,它没有任何价值,因为每个表都由我的应用程序中的一个类表示,并且所有内容都在该类中明确定义并且有据可查。

4

3 回答 3

6

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

第一个问题是您已经确定了两个类别,而不是一个,因此无法合理比较它们。

A. 第一类

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

ENUM 是非标准的;更好或标准的方法是使用查找表;那么这些值在表格中是可见的,而不是隐藏的,并且可以被任何报告工具枚举。由于内部处理,ENUM 的读取性能会受到不小的影响。

B. 第二类

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

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

当然,假设您不会做一些愚蠢的事情,例如将 8 个单独的列打包到一个 TINYINT 中。这不仅是一个严重的规范化错误,而且是编码人员的噩梦。保持每列离散且具有正确的数据类型。

C. 多指标和可空列

这与(A)和(B)无关,并且独立于(A)和(B)。列正确的数据类型是什么,与您有多少以及它是否为 Nullable 是分开的。可空意味着(通常)该列是可选的。本质上,您还没有完成建模或规范化练习。功能依赖是模棱两可的。如果你完成了规范化练习,将没有 Nullable 列,没有可选列;它们要么明显存在于特定关系,要么不存在。这意味着使用超类型-子类型的普通关系结构。

当然,这意味着更多的表,但没有 Null。Enterprise DBMS 对更多表或更多连接没有问题,这就是它们的优化目标。规范化的数据库比非规范化或非规范化的数据库执行得更好,并且它们可以在没有“重构”的情况下进行扩展。您可以通过为每个子类型提供一个视图来简化使用。

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

D. 空值的表现

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

E. 民意调查

最后,我认为这个问题的意义不是民意调查。公平地说,你会得到技术性的答案,甚至是意见,但民意调查是为了人气竞赛,而 SO 的响应者的技术能力涵盖的范围很广,所以最受欢迎的答案和技术上最正确的答案是在两个不同的光谱的末端。

于 2010-12-27T02:32:43.057 回答
1

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

例如,这里有一些替代方案将在很大程度上优于任何数据类型更改。当然,每个都有一个缺点。

如果您有 200 个可选标志,并且您一次最多查询 1-2 个用于许多行,则通过将每个标志放在自己的表中可以获得更好的性能。如果数据真的很稀疏,那就更好了。

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

如果您有一小部分标志,则可以使用位掩码将它们打包在一个列中,这在存储方面很有效,但您将无法(轻松)查询单个标志。当然,当标志可以为 NULL 时,这不起作用......

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

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

于 2010-12-27T00:08:30.270 回答
0

BOOL以上任何一项都很好,如果得到适当支持,我个人偏好使用它,因为这最能传达您的意图,但我会避免使用ENUM(0,1).

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

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

我不认为这会影响所有数据库引擎(不知道,还没有尝试过),但它会影响到足够多的数据库引擎,我认为避免它是一种好的做法。

于 2010-12-27T01:11:07.710 回答