哪个MySQL数据类型用于存储布尔值

1168 mysql boolean sqldatatypes

由于MySQL似乎没有任何"布尔"数据类型,你滥用'哪种数据类型'来存储MySQL中的真/假信息?

特别是在写入和读取PHP脚本的上下文中.

随着时间的推移,我使用并看到了几种方法:

  • tinyint,包含值0/1的varchar字段,
  • 包含字符串'0'/'1'或'true'/'false'的varchar字段
  • 最后枚举包含两个选项'true'/'false'的字段.

以上都不是最佳的.我更倾向于使用tinyint 0/1变体,因为PHP中的自动类型转换非常简单地给出了布尔值.

那你使用哪种数据类型?有没有为布尔值设计的类型,我忽略了?您是否看到使用某种类型的优点/缺点?

mar*_*kus 1202

对于MySQL 5.0.3及更高版本,您可以使用BIT.手册说:

从MySQL 5.0.3开始,BIT数据类型用于存储位字段值.一种BIT(M)允许存储M位值.M的范围为1到64.

否则,根据MySQL手册,你可以使用bool和boolean,它们是tinyint(1)的别名:

Bool,Boolean:这些类型是TINYINT(1)的同义词.值为零被视为false.非零值被认为是真实的.

MySQL还声明:

我们打算在未来的MySQL版本中按照标准SQL实现完整的布尔类型处理.

参考文献:http://dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html

  • 至少在PHP中使用char会导致更多的代码,因为`!$ boolean`永远不会在没有进一步处理的情况下正确评估. (35认同)
  • 是的,根据具体情况,我会选择这个,或者为CHAR(1)并存储'Y'/'N'或'T'/'F'等.使用小整数类型的优点是可以跨RDBMS-es获得最大的可移植性 (11认同)
  • @Pecerier你不能自己谷歌,但好吧,我会咬人.首先,请看一下data0type.h.请注意,innodb本身并没有在那里定义BIT类型.如果它以你描述的方式处理BIT字段,我们肯定会在那里找到它的存在的一些暗示.其次,请阅读http://www.mysqlperformanceblog.com/2008/04/23/efficient-boolean-value-storage-for-innodb-tables/.并且不要犹豫,启发我们"marktetplace"中哪些令人惊叹的MySQL客户端与BIT字段相匹配.毫无疑问,对于那些错过了那篇文章的人来说,它们会派上用场. (10认同)
  • 当我从标准的mysql命令行中选择时,客户端位字段显示为完全空白.因此我更喜欢TINYINT(1). (9认同)
  • @MikePurcell我不想问,但为什么你要在表示布尔值的列上使用`auto_increment`? (8认同)
  • @Pacerier"引擎可以优化多行BIT(1),优于它可以优化多行CHAR(1)".哪个"引擎"?从理论上讲,它可以.实际上,MySQL存储引擎都没有跨行包含BIT字段.坦率地说,这种打包在基于行的数据存储中毫无意义.BIT的每行打包也不是很好:如果存储引擎本身不支持BIT数据类型,MySQL服务器将MySQL BIT数据类型列映射到存储引擎中的varchar列,从而导致更多储存量超过理论最小值. (4认同)
  • 这个答案在理论上是正确的,但@Philip Morton的答案在实践中效果更好.看看[这个答案](http://stackoverflow.com/a/10542145)`由于客户端库的问题(PDO问题证明),我建议避免BIT.如果你将列的类型修改为TINYINT(1),你会给自己省去很多麻烦,这当然会消耗每一行的完整字节存储空间,但根据mysql文档,BIT(1)也会这样做. (4认同)
  • @Pacerier"使用BIT(1)你可以节省一些存储空间." 在实践中,不是真的.直到前8位仍然需要1个字节的存储空间.此外,当您大量使用命令行时,您会收到很多痛苦,因为客户端无论如何都会使用字符类型来表示位字段.最后,BIT在不同的RDBMS-es中意味着不同的东西.即使你的目标是一个MySQL解决方案,它仍然更容易坚持使用char,因为这意味着无处不在.只有在我有一个包含多个(> 8)标志的非常大的表的情况下,我才会考虑使用BIT. (3认同)
  • 切勿使用bit(1)类型来表示布尔值.至少如果要导出/导入CSV数据. (3认同)
  • @Pacerier命令行客户端是默认值 - 因此,您唯一可以依赖的是客户端.仍然好奇你可能正在谈论的其他客户"吨".关于BIT在某种程度上在语义上更正确:那是BS.BIT用于位域 - 不适用于布尔值.如果你真的那么挂在"语义"上,那么使用BOOL数据类型.这只是TINYINT(1)的同义词.您是否意识到MySQL中的TRUE和FALSE分别是int 1和int 0的同义词?坦率地说,我很惊讶你有兴趣在这么多时间之后击败这匹死马. (2认同)
  • BIT的缺点是In InnoDB中的BIT字段不能被索引(或者是索引的一部分). (2认同)

Phi*_*ton 240

BOOLBOOLEAN是同义词TINYINT(1).零是false,其他任何东西true.更多信息在这里.

  • @JamesHalsall:实际上,`BIT(1)`和`TINYINT(1)`都会使用一个字节的存储空间.直到MySQL 5.0.3,`BIT`实际上是`TINYINT`的同义词.更高版本的MySQL改变了BIT的实现.但即使实现更改,对于`BIT`数据类型仍然没有"存储大小"优势(至少对于InnoDB和MyISAM;其他存储引擎,例如NDB可能对多个BIT列声明有一些存储优化.)更大的问题是某些客户端库无法识别或正确处理返回的`BIT`数据类型列.`TINYINT`效果更好. (32认同)
  • `(1)`只是确定值的显示方式,如果你意识到存储大小,那么你想用'BIT`代替 (7认同)
  • @Walter:实际上有点真实,解释有点缺乏.简而言之,在布尔上下文中,表达式可以计算为NULL,FALSE或TRUE.在MySQL语句中,在布尔上下文中计算的表达式首先被计算为整数(十进制和浮点值被舍入,字符串以通常奇怪的方式转换,MySQL将字符串转换为整数).NULL显然是NULL(既不是TRUE也不是FALSE).整数值0表示为FALSE,*any*其他整数值(1,2,-7等)的计算结果为TRUE.为了兼容性,我们模仿TINYINT布尔值的逻辑/处理 (5认同)
  • MySQL 5.0手册清楚地说明了一个布尔值是1或0.短语"其他任何东西都是真的`"不是真的. (4认同)
  • @Walter:这很容易测试,例如`SELECT'foo'AS bar FROM dual WHERE -7`.表达式-7在布尔上下文中计算,查询返回一行.我们可以使用0或任何计算结果为整数值0的表达式进行测试,并且不返回任何行.如果WHERE子句中的表达式求值为除零以外的任何非null整数值,则表达式为TRUE.(我相信decimal和float值会被"舍入"为整数,例如`WHERE 1/3`计算结果为`WHERE 0`.我们得到与`WHERE'foo'`相同的结果,因为字符串''foo'`也会评估到整数值0. (3认同)

小智 68

这是一个优雅的解决方案,我非常欣赏,因为它使用零数据字节:

some_flag CHAR(0) DEFAULT NULL
Run Code Online (Sandbox Code Playgroud)

要将其设置为true,请设置some_flag = ''并将其设置为false,然后设置some_flag = NULL.

然后测试是否为true,检查是否为some_flag IS NOT NULL,并测试是否为false,检查是否为some_flag IS NULL.

(这种方法在Jon Warren Lentz,Baron Schwartz和Arjen Lentz的"High Performance MySQL:Optimization,Backups,Replication,and More"中有描述.)

  • 可能是"快速",但它会混淆数据,以至于任何新的开发人员都不知道该列代表什么. (57认同)
  • 祝ORM能够很好地映射到这一点. (25认同)
  • 这使用与BIT(1)相同的字节数 (5认同)
  • 我同意@Richthofen,并且很难想象我会主张使用这个解决方案的情况.但是,如果要使用它,那么在列的定义中指定为"COMMENT","NULL"表示false,而""表示为true,可能会在帮助未来理解方面采取一些非常小的方式. (4认同)
  • 花哨的把戏!如果使用MySQL <5并且甚至可能比BIT更轻的占用空间,这是有帮助的,但是为了遵守约定并且稍微减少计算开销(逻辑与精确值),我会说BIT是更好的方法. (3认同)

Cia*_*lty 34

如果使用BOOLEAN类型,则将其别名为TINYINT(1).如果您想使用标准化SQL并且不介意该字段可能包含超出范围的值(基本上任何非0的内容都将为'true'),这是最好的.

ENUM('False','True')将允许您使用SQL中的字符串,并且MySQL将在内部将字段存储为整数,其中'False'= 0并且'True'= 1,基于指定Enum的顺序.

在MySQL 5+中,您可以使用BIT(1)字段来指示1位数字类型.我不相信这实际上在存储中使用了更少的空间,但是再次允许您将可能的值约束为1或0.

以上所有内容都将使用大致相同的存储空间,因此最好选择最容易使用的存储空间.

  • 你关于ENUM的评论是不正确的:尝试CAST(yourenumcol AS UNSIGNED),你会注意到False将是1,True将是2. ENUM的另一个问题是它太容易插入''(空字符串) ).我不赞成使用它. (8认同)
  • 根据我的经验,使用PHP代码中的BIT(1)字段有点麻烦.TINYINT(1)更容易,并且生成更易读的代码. (4认同)
  • @BMiner - 哈哈,它真的是无意识的,没有注意到:)但实际上,如果我没记错,比特字段被解释为二进制,而tinyint更容易被视为一个数字,因此,更容易在(布尔)表达式中使用. (2认同)

Jos*_*osh 34

这个问题已得到解答,但我想我会投入0.02美元.我经常使用CHAR(0),其中''== true和NULL == false.

来自mysql文档

当你需要一个只能有两个值的列时,CHAR(0)也很好:一个定义为CHAR(0)的列只占用一位,只能取值NULL和''(空字符串) .

  • 嗯,如果你像我一样,这似乎是在惹麻烦.我的意思是,根据语言,可能很容易发现NULL和''之间的差异(例如PHP). (15认同)
  • 在节省空间(用于表示布尔值的字节数)方面,这种方法是明显的赢家.这样可以在TINYINT上保存一个字节.缺点(正如一些评论所指出的)是一些客户可能难以区分NULL和空字符串.甚至一些关系数据库(例如Oracle)也不区分零长度字符串和NULL. (3认同)
  • 这很聪明!我曾经写过聪明的代码,现在我像瘟疫一样避免它.我现在希望我的代码具有明确的意图,而不仅仅是正确的行为.我的建议?只有当你想混淆那些必须支持代码/数据库的人时才这样做.例如,在PHP中,'''和`null`都是假值. (3认同)
  • @CJDennis 如果您在存储库模式后面抽象了数据库层,则不必担心此解决方案的晦涩难懂。 (2认同)

Fre*_*red 18

我使用TINYINT(1)来在Mysql中存储布尔值.

我不知道使用这个是否有任何好处...但如果我没有错,mysql可以存储boolean(BOOL)并将其存储为tinyint(1)

http://dev.mysql.com/doc/refman/5.0/en/other-vendor-data-types.html


Tho*_*hor 17

如果你有很多布尔字段,Bit只对各种字节选项(tinyint,enum,char(1))有利.一位字段仍占用一个完整字节.两个位字段适合同一个字节.三,四,五,六,七,八.之后他们开始填写下一个字节.最终节省的成本非常小,您应该关注数以千计的其他优化.除非您处理大量数据,否则这几个字节不会增加太多.如果您在PHP中使用bit,则需要对输入和输出的值进行类型转换.


小智 12

在MySQL实现位数据类型之前,如果您的处理真正按空间和/或时间(例如高容量事务),请创建一个bit_flags为所有布尔变量调用的TINYINT字段,并在SQL中屏蔽并移动所需的布尔位查询.

例如,如果你的最左边的位代表你的bool字段,而最右边的7位代表什么,那么你的bit_flags字段将等于128(二进制10000000).掩盖(隐藏)最右边的七个位(使用按位运算符&),并将第8位向右移动七个空格,最后用00000001.现在整个数字(在本例中为1)是你的值.

SELECT (t.bit_flags & 128) >> 7 AS myBool FROM myTable t;

if bit_flags = 128 ==> 1 (true)
if bit_flags = 0 ==> 0 (false)
Run Code Online (Sandbox Code Playgroud)

您可以在测试时运行这些语句

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;
Run Code Online (Sandbox Code Playgroud)

等等

由于您有8位,因此一个字节可能有8个布尔变量.一些未来的程序员将总是使用接下来的七位,所以你必须掩盖.不要只是转移,否则你将来会为自己和他人制造地狱.确保你有MySQL进行屏蔽和转移 - 这比使用网络脚本语言(PHP,ASP等)做得快得多.此外,请确保在您的bit_flags字段的MySQL注释字段中添加注释.

在实现此方法时,您会发现这些网站很有用:

  • 这似乎是一种混淆未来程序员意图的可怕方式.当然,保存7个字节似乎很麻烦(假设您在该单个表中使用了所有8个bool!) (6认同)

Geo*_*all 10

我厌倦了尝试获得零,NULLS,并且''准确地围绕PHP,MySql和POST值循环,所以我只使用'是'和'否'.

这种方法完美无缺,不需要特别的处理,这种处理不明显且容易做到.

  • 如果你真的想浪费这么多空间并降低性能,你至少可以用Y和N选项完成CHAR(1). (17认同)
  • 这个答案没有错,因为它会起作用,并没有人们给它的功劳那么糟糕.对于大多数项目(即:表格大小<1mil行)提供的解决方案之间的性能差异将是可忽略的.如果我的查询在7到5毫秒内返回,我不会抱怨......但是,如果你的表增长到10mil或更多行,这可能不是首选解决方案. (8认同)
  • 在大多数现实世界的情况下,"不"和仅仅缺少信息之间存在真正的差异.例如,如果用户实际上没有说"不",您可能希望默认选中一个复选框.你认为你节省多少空间,每次你需要区分一个假和一个NULL时你做了多少处理 - 如果你确实可以区分?在存储图像和数字视频的世界中,节省空间的一两个点完全无关紧要,但清晰度和减少的处理是真实的. (3认同)
  • 我为使用 ENUM 数据类型而+1。我个人更喜欢这种表示法:ENUM('y','n')。它是紧凑的(只有一个字节长)、直观且美观,作为所有布尔标志的应用程序级约定。您可以直接将其与 HTML 表单字段一起使用。例如使用 PHP: &lt;select name="product"&gt; &lt;option value="y"&lt;?=$product === 'y'? ' selected="selected"' : ''?&gt;&gt;是&lt;/option&gt; &lt;option value="n"&lt;?=$product === 'n'? ' selected="selected"' : ''?&gt;&gt;否&lt;/选项&gt; &lt;/选择&gt; (2认同)
  • 大声笑我的眼睛,但我不得不说@GeoffKendall是对的.在很多情况下,不需要最佳性能,无论何种方法,您的工作都是正确的方法. (2认同)

Vid*_*idz 6

参考Mysql中的这个链接 布尔数据类型,根据应用程序的用法,如果只想存储0或1,则bit(1)是更好的选择.

  • 确实,'BIT(1)`只允许存储'b'0'或'b'1'.值.`BIT`数据类型的最大问题是各种客户端库对数据类型有各种不稳定的处理.检查各种SQL工具(SQLyog,TOAD for MySQL,SQL Developer)中的行为,"反向工程"数据库模型的工具,以及各种客户端,如JDBC,PHP,Perl DBI,并且为了更好的衡量,测试一些ORM框架( Hibernate,Mybatis,JPA).在易用性,工具/框架兼容性/原生支持方面,`TINYINT(1)`是明显的赢家. (6认同)

Pau*_*gel 6

由于 MySQL (8.0.16) 和 MariaDB (10.2.1) 都实现了 CHECK 约束,我现在将使用

bool_val TINYINT CHECK(bool_val IN(0,1))
Run Code Online (Sandbox Code Playgroud)

您将只能存储0,1NULL以及可以转换为01没有错误的值,例如'1', 0x00,b'1'TRUE/ FALSE

如果您不想允许 NULL,请添加NOT NULL选项

bool_val TINYINT NOT NULL CHECK(bool_val IN(0,1))
Run Code Online (Sandbox Code Playgroud)

请注意,如果您使用TINYINT,TINYINT(1)或,则几乎没有区别TINYINT(123)

如果您希望您的架构向上兼容,您还可以使用BOOLBOOLEAN

bool_val BOOL CHECK(bool_val IN(TRUE,FALSE))
Run Code Online (Sandbox Code Playgroud)

db<>小提琴演示

  • @santiagoarizti `ENUM` (它必须是 `enum('0', '1')` - 注意:这些是字符串)不是一个好主意。由于内部存储方式以及非字符串值的处理方式,存在[太多问题](https://dbfiddle.uk/?rdbms=mysql_8.0&amp;fiddle=f5e08772c7cea401ec1d66c8707734c3)。例如。无法存储“0”和“FALSE”。“1”和“TRUE”变为“0”。并且“2”变成了“1”。 (3认同)

Lem*_*res 5

阅读完这里的答案后,我决定使用它bit(1),是的,它在空间/时间上在某种程度上更好,过了一段时间我改变了主意,我再也不会使用它了。当使用准备好的语句、库等(php)时,它使我的开发变得非常复杂。

从那时起,我一直使用tinyint(1),似乎足够好。

  • 愿意解释一下它在哪些方面使您的开发变得复杂吗? (3认同)