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


1207

由于MySQL似乎没有任何“布尔”数据类型,因此您“滥用”哪种数据类型在MySQL中存储对/错信息?

尤其是在从PHP脚本进行读写的情况下。

随着时间的流逝,我已经使用并看到了几种方法:

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

以上都不是最佳选择。我倾向于使用tinyint 0/1变体,因为PHP中的自动类型转换使我可以很简单地获得布尔值。

那么,您使用哪种数据类型?是否有为我忽略的布尔值设计的类型?通过使用一种或另一种类型,您是否看到任何优点/缺点?


217
任何正在阅读该问题的旧答案的人都需要了解MySQL在版本5中添加了一点数据类型。请尽可能使用该信息。dev.mysql.com/doc/refman/5.0/en/bit-type.html
smp7d


7
对于当前版本的MYSQL,布尔类型可用-dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html进行检查。根据该值零被视为错误
DevT 2012年

7
bit(1)有点要导入Excel。切换到tinyint(1)工程。
Cees Timmerman 2014年

8
现在我们已经过了5年的布尔值
V-SHY 2014年

Answers:


1232

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

从MySQL 5.0.3开始,BIT数据类型用于存储位字段值。BIT(M)类型可以存储M位的值。M的范围是1到64。

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

Bool,布尔值:这些类型是TINYINT(1)的同义词。零值被认为是错误的。非零值被认为是正确的。

MySQL还指出:

我们打算在将来的MySQL版本中根据标准SQL实现完整的布尔类型处理。

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


11
是的,我会选择使用此函数,或者使用CHAR(1)并根据上下文存储“ Y” /“ N”或“ T” /“ F”等。使用小整数类型的优点是您可以跨RDBMS-es获得最大的可移植性
Roland Bouman 2010年

36
至少在PHP中,使用char会导致更多代码,因为!$boolean未经进一步处理就无法正确评估。
轻度绒毛

10
@Pecerier没什么,你自己不能用谷歌搜索,但是好吧,我会咬。首先,请看一下data0type.h。请注意,innodb没有在本地定义BIT类型。如果以您描述的方式对待BIT字段,那么我们肯定会在其中找到其存在的一些暗示。其次,阅读mysqlperformanceblog.com/2008/04/23/…。并且请毫不犹豫地启发我们“ marktetplace”中哪些出色的MySQL客户端与BIT字段配合使用。无疑,对于任何错过该文章的人,它们将派上用场。
罗兰·鲍曼

9
当我从标准mysql命令行中进行选择时,客户端位字段显示为完全空白。因此,我更喜欢TINYINT(1)。
用户

8
我讨厌问@MikePurcell,但是为什么要auto_increment在表示布尔值的列上呢?
克里斯·海斯

248

BOOLBOOLEAN是的同义词TINYINT(1)。零是false,其他就是true。更多信息在这里


7
这样(1)做无非决定值的显示方式,如果您了解存储大小,则可以使用它BIT代替
JamesHalsall 2014年

35
@JamesHalsall:其实,BIT(1)并且TINYINT(1)将存储都使用一个字节。直到MySQL 5.0.3,BIT实际上是的同义词TINYINT。MySQL的更高版本更改了BIT的实现。但是,即使实现更改,BIT数据类型仍然没有“存储大小”的好处(至少使用InnoDB和MyISAM;其他存储引擎(例如NDB)可能对多个BIT列声明进行了一些存储优化。)更大的问题是某些客户端库无法识别或适当处理返回的BIT数据类型列。一个TINYINT更好的作品。
spencer7593 2014年

5
MySQL 5.0手册明确指出布尔值是1或0。短语“其他任何东西true”都不正确。
Walter

7
@沃尔特:这实际上是对的,缺乏解释。简而言之,在布尔上下文中,表达式可以求值为NULL,FALSE或TRUE。在MySQL语句中,首先将在布尔上下文中评估的表达式评估为整数(十进制和浮点值四舍五入,以通常的古怪方式MySQL将字符串转换为整数来转换字符串)。NULL显然是NULL(既不是TRUE也不是FALSE)。整数值0视为FALSE,其他任何整数值(1、2,-7等)的计算结果均为TRUE。为了兼容性,我们模拟了TINYINT布尔值的逻辑/处理
spencer7593

4
@Walter:这很容易测试,例如 SELECT 'foo' AS bar FROM dual WHERE -7。表达式-7在布尔上下文中求值,查询返回一行。我们可以用0或任何计算结果为整数值0的表达式进行测试,而不会返回任何行。如果WHERE子句中的表达式求值为非零的任何非空整数值,则该表达式为TRUE。(我相信,十进制和浮点值获得“四舍五入”到整数,例如WHERE 1/3计算结果为WHERE 0我们得到同样的结果。WHERE 'foo'因为字符串'foo'也计算为整数值0
spencer7593

71

这是一个很好的解决方案,我非常感谢,因为它使用零数据字节:

some_flag CHAR(0) DEFAULT NULL

要将其设置为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撰写的“高性能MySQL:优化,备份,复制和更多功能中进行了描述”。)


3
花哨的把戏!如果使用MySQL <5甚至比BIT更轻的内存,这将很有帮助,但是为了遵守约定并略微减少计算开销(逻辑与精确值),我想说BIT是更好的选择。
zamnuts 2012年

59
可能是“快速”的,但它会混淆数据,以至于任何新开发人员都不知道该列代表什么。
Richthofen

5
这使用的字节数与BIT(1)相同
ITS阿拉斯加

25
祝您好运,ORM可以很好地对此进行映射。
Craig Labenz

4
我同意@Richthofen,并且很难想象有一种情况会提倡使用此解决方案。但是,如果要使用它,则COMMENT在列的定义中将a指定为NULLfalse并''指示true可能会以很小的方式帮助将来的理解。
eggyal 2015年

34

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

ENUM('False','True')将允许您在SQL中使用字符串,而MySQL将根据指定Enum的顺序在内部将字段存储为整数,其中'False'= 0和'True'= 1 。

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

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


8
您对ENUM的评论不正确:尝试使用CAST(yourenumcol AS UNSIGNED),您会发现False将为1,True将为2。ENUM的另一个问题是插入''(空字符串)太容易了)。我不建议使用此功能。
罗兰·鲍曼

4
以我的经验,使用PHP代码中的BIT(1)字段有点麻烦。TINYINT(1)容易得多,并且产生了更具可读性的代码。
M-Peror 2011年

1
@ M-Peror-“使用PHP代码中的BIT(1)字段有点麻烦”……没有双关语。:)但是,是的,我同意。我记得TINYINT(1)也更容易...只是不记得为什么。还有其他人对此有想法吗?从表面上看,BIT(1)看起来更好,因为您可以限制为0或1。我认为BIT有时被解释为二进制数据(取决于编程语言和驱动程序/库)。而TINYINT则被视为数字。
BMiner 2011年

2
@BMiner-哈哈,这确实是意料之外的,没有注意到:)但是,确实,如果我没记错的话,将位字段解释为二进制的内容,而tinyint更易于视为数字,因此,更容易在(布尔)表达式中使用。
M-Peror 2011年

34

这个问题已经回答了,但我认为我要投入0.02美元。我经常CHAR(0)在哪里使用'' == true and NULL == false

mysql文档

CHAR(0)当您需要只能包含两个值的列时,它也非常好:被定义为的列CHAR(0) NULL仅占用一位,并且只能接受值NULLand ''(空字符串)。


16
嗯,如果您和我一样,这似乎是在自找麻烦。我的意思是,根据语言的不同,可能很容易无法发现NULL和''之间的差异(例如PHP)。
罗兰·鲍曼

3
就节省空间(用于表示布尔值的字节数)而言,此方法无疑是赢家。这样可以在TINYINT上节省一个字节。不利的一面(如一些评论所指出的)是某些客户端可能难以区分NULL和空字符串。甚至某些关系数据库(例如Oracle)也无法区分零长度字符串和NULL。
spencer7593 2015年

3
这非常聪明!我曾经写过聪明的代码,现在却像瘟疫一样避免使用它。我现在希望我的代码具有明确的意图,而不仅仅是正确的行为。我的建议?仅当您想混淆必须支持代码/数据库的任何人时,才这样做。例如,在PHP中,''null都是伪造的值。
CJ丹尼斯

1
@CJDennis如果您已在存储库模式之后抽象了数据库层,则不必担心此解决方案的晦涩之处。
prograhammer'1


17

如果您有很多布尔字段,则位仅比各种字节选项(tinyint,枚举,char(1))更有利。一位字段仍占据整个字节。两个位字段适合同一字节。三,四,五,六,七,八。之后,他们开始填充下一个字节。最终,节省的资金是如此之小,您应该关注数千种其他优化。除非您要处理大量数据,否则这几个字节不会累加太多。如果您在PHP中使用bit,则需要对传入和传出的值进行类型转换。


1
+1类型转换注释。要在使用编程语言时对此加以补充,请避免使用倾向于一致性的惰性编程技术。使用相同的运算符,而不是仅等于。对于PHP,if($ var ==“”)对于0,false,null,undefined和“”将为true。要测试所有值,通常最好使用if(true === empty($ var)),因为这样也可以避免未定义的错误。您还应该验证正在使用if(is_int($ var)&& $ var === 0)的数据类型,或者强制转换它以使其成为任务的特定数据类型(int)$ var。
fyrye

@Thor在MySQL方面与MSSQL一样适用吗?我正在将尚未投入生产的新应用程序从MSSQL迁移到MySQL。我不是在使用PHP,而是将C#转换为Java8。考虑到Java是一种强类型语言,我不必担心类型处理……只是所有位标志会从一个字节移动到最多8个标志,给定TINYINT(1)的每个标志1个字节。您是否知道有关MySQL的此主题的任何文档?
Zack Jannsen

1
@Thor经过更深入的研究,很清楚答案应该是什么。确实发生了变化,并且我们已经看到这种处理方面的改进。了解将在应用程序层/数据访问层中使用的语言,并了解您的库支持。我目前正在使用Java,对于像Hybernate这样的库和JDBC,目前推荐使用BIT(1)。这里是URL [见表5.2]:dev.mysql.com/doc/connector-j/en/...
扎克Jannsen

12

在MySQL实现位数据类型之前,如果确实需要处理以节省空间和/或时间(例如处理大量事务),请bit_flags为所有布尔变量创建一个TINYINT字段,并在SQL中屏蔽和移位所需的布尔位查询。

例如,如果您最左边的位代表bool字段,而最右边的7位不代表任何内容,那么您的bit_flags字段将等于128(二进制10000000)。屏蔽(隐藏)最右边的7位(使用按位运算符&),并将第8位向右移动7个空格,最后为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)

您可以在测试时运行此类语句

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

等等

由于您有8位,因此一个字节中可能有8个布尔变量。将来的某些程序员将始终使用接下来的7位,因此必须屏蔽。不要只是转变,否则将来您会为自己和他人制造地狱。确保使用MySQL进行掩蔽和转换-这比使用Web脚本语言(PHP,ASP等)要快得多。另外,请确保在您的bit_flags字段的MySQL注释字段中放置注释。

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


7
这似乎是一种使将来的程序员难以理解的可怕方法。当然,保存7个字节似乎很麻烦(假设您在单个表中使用了所有8个布尔值!)
是的,

@yep根本没有混淆!编写文档和MySQL 注释来解释表中的每个字段(如答案所述)!建议的MySQL取消屏蔽策略看起来很可靠,最多存储16个不同的布尔字段(仅包含几列)要好于拥有16 。如果使用位操作太令人困惑,并且您更喜欢使用Web脚本语言来获取每个布尔值,只需将其存储为a VARCHAR并在代码中执行解屏蔽过程即可(您也不必将其限制为8个字段) ...
CPHPython


10

我受够了尝试获取零,NULL和''准确地绕过PHP,MySql和POST值的循环,所以我只使用了“是”和“否”。

这可以完美地工作,并且不需要特殊的处理,这些处理不是显而易见的,也不是容易做到的。


17
如果您确实想浪费这么多空间并损害性能,则可以至少使用Y和N选项完成CHAR(1)。
ILikeTacos 2013年

3
在大多数现实世界中,“不”与仅缺少信息之间存在着真正的区别。例如,如果用户实际上尚未说“否”,则可能希望默认选中一个复选框。您认为您确实节省了多少空间,并且每次需要区分一个假值和一个NULL值时,您会做多少处理-如果确实可以区分的话?在存储图像和数字视频的世界中,节省一点点空间根本不相关,但是清晰度和减少的处理是真实的。
2014年

8
这个答案没有错,因为它会起作用,而且还没有人们认为的那么糟糕。对于大多数项目(即:表大小<100万行),提供的解决方案之间的性能差异可以忽略不计。我不会抱怨查询返回的时间是7毫秒还是5毫秒...公平地说,如果您的表增长到1000万行或更多,这可能不是首选解决方案。
布拉德(Brad)2014年

1
向我+1以使用ENUM数据类型。我个人更喜欢这种表示法:ENUM('y','n')。作为所有布尔标志的应用程序级约定,它紧凑(仅一个字节长),直观且美观。您可以将其直接用于HTML表单字段。例如使用PHP:<select name =“ production”> <option value =“ y” <?= $ production ==='y'?'selected =“ selected”':''?>>是</ option> <option value =“ n” <?= $ production ==='n'?'selected =“ selected”':''?>>否</ option> </ select>
Vlado 2014年

2
大声笑这让我大吃一惊,但我不得不说@GeoffKendall是正确的。在很多情况下,不需要最佳性能,而适合您的方法是正确的方法。
Madmenyo 2015年

6

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


6
确实BIT(1)只允许存储一个b'0'b'1'值。BIT数据类型的最大问题是,各种客户端库对数据类型都有各种处理方式。在各种SQL工具(SQLyog,MySQL的TOAD,SQL Developer),对数据库模型进行“反向工程”的工具以及各种客户端(例如JDBC,PHP,Perl DBI)中检查行为,并在很好的情况下,测试一些ORM框架(休眠,Mybatis,JPA)。在易用性方面,工具/框架兼容性/本机支持TINYINT(1)无疑是赢家。
spencer7593 2015年

是。它的完成取决于所考虑的应用程序框架。例如,PHP的Phalcon框架不处理Bit数据类型
Vidz

作为记录,MyBatis同时支持BITTINYINT。请参阅MyBatis的JdbcType
幸运

1
@Vidz我给您提供一个额外的提及BIT(1)的信息,但同时也会指出开发人员正在阅读的内容-了解您将在应用程序层/数据访问层中使用的语言,并了解您的库支持。我目前正在使用Java,目前建议将BIT(1)用于Hybernate之类的库和JDBC的使用。这里是URL [见表5.2]:dev.mysql.com/doc/connector-j/en/...
扎克Jannsen

6

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

bool_val TINYINT CHECK(bool_val IN(0,1))

您将只能够存储01或者NULL,也可以转换为数值01不类似的错误'1'0x00b'1'TRUE/ FALSE

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

bool_val TINYINT NOT NULL CHECK(bool_val IN(0,1))

注意,这里几乎没有区别,如果你使用TINYINTTINYINT(1)TINYINT(123)

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

bool_val BOOL CHECK(bool_val IN(TRUE,FALSE))

db <> fiddle演示


枚举(0,1)
圣地亚哥·亚利桑那

3
@santiagoarizti ENUM(必须enum('0', '1')-注意:这些是字符串)不是一个好主意。由于它如何在内部存储以及如何处理非字符串值,因此存在太多问题。例如。0并且FALSE 无法存储。1TRUE成为'0'。并2成为'1'
Paul Spiegel

最佳答案...对于使用MySQL 8+的用户
dolmen

2

在阅读了这里的答案后,我决定使用bit(1)它,是的,它在时空上有所改善,但是一段时间后我改变了主意,我将不再使用它。当使用准备好的语句,库等(php)时,这使我的开发变得非常复杂。

从那时起,我一直使用tinyint(1),似乎还不错。


3
努力说明以什么方式使您的开发复杂化?
Chazy Chaz

@ChazyChaz期望true / false而不是1/0,这与SQL Server等其他数据库不同。有时这会导致奇怪的情况,您认为您将其设置为true,但实际上并没有发生。
maembe

0

您可以使用BOOL,BOOLEAN数据类型来存储布尔值。

这些类型是TINYINT(1)的同义词

但是,使用BIT(1)数据类型来存储布尔值(true [1]或false [0])更有意义,但在输出数据,进行查询等操作时,TINYINT(1)更易于使用并实现MySQL与其他数据库之间的互操作性。您也可以检查此答案或主题

MySQL还将BOOL,BOOLEAN数据类型转换为TINYINT(1)。

此外,请阅读文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.