Qual tipo de dados MySQL usar para armazenar valores booleanos

1208

Como o MySQL não parece ter nenhum tipo de dados 'booleano', que tipo de dados você 'abuse' por armazenar informações verdadeiras / falsas no MySQL?

Especialmente no contexto de escrita e leitura de / para um script PHP.

Com o tempo, usei e vi várias abordagens:

  • tinyint, campos varchar contendo os valores 0/1,
  • campos varchar contendo as seqüências de caracteres '0' / '1' ou 'true' / 'false'
  • e finalmente enum Campos contendo as duas opções 'true' / 'false'.

Nenhuma das opções acima parece ótima. Eu tendem a preferir a variante tinyint 0/1, pois a conversão automática de tipo no PHP me fornece valores booleanos de maneira bastante simples.

Então, qual tipo de dados você usa? Existe um tipo projetado para valores booleanos que eu ignorei? Você vê vantagens / desvantagens usando um tipo ou outro?

Peter Mortensen
fonte
217
Qualquer pessoa que esteja lendo as respostas antigas para esta pergunta precisa entender que o MySQL adicionou um tipo de dados pouco na versão 5. Use essas informações como desejar. dev.mysql.com/doc/refman/5.0/en/bit-type.html
smp7d
3
Pergunta relacionada a Alternativa para muitos booleanos no MySQL?
tereško
7
para a versão atual do tipo booleano MYSQL está disponível - dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html, verifique isso. de acordo com esse valor zero considerado falso
DevT 29/08/2012
7
bit(1)é um pouco ** para importar no Excel. Mudando para o tinyint(1)Works.
Cees Timmerman
8
agora temos booleano depois de 5 anos
V-SHY 14/03

Respostas:

1232

Para o MySQL 5.0.3 e superior, você pode usar BIT . O manual diz:

A partir do MySQL 5.0.3, o tipo de dados BIT é usado para armazenar valores de campo de bits. Um tipo de BIT (M) permite o armazenamento de valores de M bits. M pode variar de 1 a 64.

Caso contrário, de acordo com o manual do MySQL, você pode usar bool e boolean, que são atualmente aliases de tinyint (1):

Booleano: Estes tipos são sinônimos para TINYINT (1). Um valor zero é considerado falso. Valores diferentes de zero são considerados verdadeiros.

O MySQL também afirma que:

Pretendemos implementar um tratamento completo do tipo booleano, de acordo com o SQL padrão, em uma versão futura do MySQL.

Referências: http://dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html

markus
fonte
11
Sim, eu usaria isso ou, para um CHAR (1) e armazenaria 'Y' / 'N' ou 'T' / 'F' etc., dependendo do contexto. A vantagem de usar um pequeno tipo inteiro é que você obter o máximo de portabilidade entre RDBMS-es
Roland Bouman
36
Adotar char, pelo menos em PHP, levará a mais código, pois !$booleannunca será avaliado adequadamente sem processamento adicional.
Fuzz suave
10
@ Pecerier Nada que você não possa pesquisar no google, mas ok, eu vou morder. Primeiro de tudo, dê uma olhada no data0type.h. Observe que o innodb não define nativamente um tipo de BIT lá. Se tratasse os campos BIT da maneira que você descreve, certamente encontraríamos alguma dica de sua existência lá. Em segundo lugar, leia mysqlperformanceblog.com/2008/04/23/… . E não hesite em esclarecer quais clientes surpreendentes do MySQL no "marktetplace" funcionam bem com os campos BIT. Eles serão úteis para quem perdeu esse artigo, sem dúvida.
Roland Bouman
9
Quando eu faço uma seleção nos campos de bits do cliente da linha de comando padrão do mysql, aparece completamente em branco. Por isso, prefiro o TINYINT (1).
Utilizador
8
@ MikePurcell Eu odeio perguntar, mas por que você quer auto_incrementuma coluna representando um valor booleano?
Chris Hayes
248

BOOLe BOOLEANsão sinônimos de TINYINT(1). Zero é false, qualquer outra coisa é true. Mais informações aqui .

Philip Morton
fonte
7
A (1)não faz nada mais do que determinar como o valor é exibido, se você está consciente sobre tamanho de armazenamento, em seguida, que pretende utilizar BITem vez
JamesHalsall
35
@ JamesHalsall: Na verdade, BIT(1)e TINYINT(1)ambos usarão um byte de armazenamento. Até o MySQL 5.0.3, BITna verdade era sinônimo TINYINT. Versões posteriores do MySQL mudaram a implementação do BIT. Mas mesmo com a alteração na implementação, ainda não há benefício de "tamanho do armazenamento" para o BITtipo de dados (pelo menos com o InnoDB e o MyISAM; outros mecanismos de armazenamento, como o NDB, podem ter alguma otimização de armazenamento para várias declarações de coluna BIT.) O maior problema é que alguns clientes as bibliotecas não reconhecem ou tratam adequadamente as BITcolunas de tipo de dados retornadas . A TINYINTfunciona melhor.
Spencer7593
5
O manual do MySQL 5.0 diz claramente que um valor booleano é 1 ou 0. A frase "qualquer outra coisa é true" não é verdadeira.
Walter
7
@ Walter: Na verdade, é meio que verdade, a explicação está faltando. Resumidamente, em um contexto booleano, uma expressão pode ser avaliada como NULL, FALSE ou TRUE. Em uma instrução MySQL, uma expressão avaliada em um contexto booleano é avaliada primeiro como inteiro (os valores decimais e flutuantes são arredondados, as seqüências de caracteres são convertidas da maneira peculiar que o MySQL converte as seqüências de caracteres em números inteiros). Um NULL é obviamente NULL (nem VERDADEIRO nem FALSO). Um valor inteiro 0 é tratado como FALSE, e qualquer outro valor inteiro (1, 2, -7, etc) é avaliado como TRUE. Para compatibilidade, que imitam essa lógica / manuseio de TINYINT booleano
spencer7593
4
@ Walter: Isso é fácil de testar, por exemplo SELECT 'foo' AS bar FROM dual WHERE -7. A expressão -7 é avaliada em um contexto booleano e a consulta retorna uma linha. Podemos testar com 0 ou qualquer expressão que avalie o valor inteiro 0 e nenhuma linha é retornada. Se a expressão na cláusula WHERE for avaliada como qualquer valor inteiro não nulo diferente de zero, a expressão será TRUE. (Eu acredito valores decimais e flutuador obter "arredondado" para inteiro, por exemplo, WHERE 1/3avalia a WHERE 0Nós obter o mesmo resultado com. WHERE 'foo', Porque corda 'foo'também avalia a valor inteiro 0.
spencer7593
71

Esta é uma solução elegante que eu aprecio bastante porque usa zero bytes de dados:

some_flag CHAR(0) DEFAULT NULL

Para configurá-lo como true, configure some_flag = ''e para false, configuresome_flag = NULL .

Em seguida, para testar se true, verifique se some_flag IS NOT NULLe, para testar false, verifique se some_flagIS NULL .

(Este método é descrito em "MySQL de alto desempenho: otimização, backups, replicação e muito mais", de Jon Warren Lentz, Baron Schwartz e Arjen Lentz.)

RS
fonte
3
truque chique! isso é útil se você estiver trabalhando com o MySQL <5 e talvez até com menos espaço do que o BIT, no entanto, em um esforço para cumprir a convenção e um pouco menos sobrecarga de computação (valor lógico versus exato), eu diria que o BIT é o melhor caminho a percorrer.
Zamnuts
59
Pode ser "rápido", mas ofusca os dados de forma que qualquer novo desenvolvedor não tenha idéia do que a coluna representa.
Richthofen
5
Este é utiliza a mesma quantidade de bytes como BIT (1)
A SUA Alaska
25
Boa sorte em conseguir que um ORM seja bem mapeado para isso.
Craig Labenz
4
Eu concordo com @Richthofen e acho difícil imaginar uma situação em que eu advogaria o uso dessa solução. No entanto, se for para ser usado, especificar como COMMENTna definição da coluna que NULLindica falso e ''indica verdadeiro pode ser muito pequeno para ajudar no entendimento futuro.
eggyal 21/03/2015
34

Se você usar o tipo BOOLEAN, isso é alias para TINYINT (1). Isso é melhor se você quiser usar SQL padronizado e não se importar que o campo possa conter um valor fora do intervalo (basicamente qualquer coisa que não seja 0 será 'verdadeira').

ENUM ('False', 'True') permitirá que você use as strings em seu SQL, e o MySQL armazenará o campo internamente como um número inteiro onde 'False' = 0 e 'True' = 1 com base na ordem em que o Enum está especificado .

No MySQL 5+, você pode usar um campo BIT (1) para indicar um tipo numérico de 1 bit. Não acredito que isso realmente use menos espaço no armazenamento, mas novamente permita que você limite os valores possíveis para 1 ou 0.

Todas as opções acima usarão aproximadamente a mesma quantidade de armazenamento; portanto, é melhor escolher a que você achar mais fácil trabalhar.

Ciaran McNulty
fonte
8
Sua observação sobre o ENUM não é verdadeira: tente CAST (seuenumcol COMO NÃO ASSINADO) e você notará que False será 1 e True será 2. Outro problema com ENUM é que é muito fácil inserir '' (seqüência vazia ) Eu não recomendaria usar isso.
Roland Bouman
4
Na minha experiência, usar um campo BIT (1) do código PHP foi um pouco problemático. TINYINT (1) foi muito mais fácil e produziu um código mais legível.
precisa saber é o seguinte
1
@ M-Peror - "usar um campo BIT (1) do código PHP foi um pouco problemático" ... sem trocadilhos. :) Mas sim, eu concordo. Lembro-me de TINYINT (1) ser mais fácil também ... só não consigo lembrar o porquê. Alguém mais tem pensamentos sobre isso? O BIT (1) parece melhor na superfície porque você pode restringir a 0 ou 1. Acho que o BIT às vezes foi interpretado como dados binários (dependendo da linguagem de programação e do driver / biblioteca); enquanto TINYINT foi tratado mais como um número.
BMiner
2
@BMiner - haha, foi realmente não intencional, não percebeu isso :) Mas, de fato, se bem me lembro, o campo de bits foi interpretado como algo binário, enquanto o tinyint era mais fácil de tratar como um número e, por isso, mais fácil de use em uma expressão (booleana).
M-Peror
34

Esta pergunta foi respondida, mas achei que jogaria meus $ 0,02. Eu costumo usar um CHAR(0), onde'' == true and NULL == false .

Dos documentos do mysql :

CHAR(0)também é bastante bom quando você precisa de uma coluna que pode ter apenas dois valores: Uma coluna definida como CHAR(0) NULLocupa apenas um bit e pode receber apenas os valores NULLe ''(a sequência vazia).

Josh
fonte
16
mm, isso parece pedir problemas se você como eu. Quero dizer, dependendo da linguagem, pode ser muito fácil não identificar a diferença entre NULL e '' (por exemplo, PHP).
Roland Bouman
3
Em termos de economia de espaço (o número de bytes usados ​​para representar um booleano), essa abordagem é uma clara vencedora. Isso economiza um byte sobre TINYINT. A desvantagem (como alguns comentários apontam) é que alguns clientes podem ter dificuldade em distinguir entre uma seqüência NULL e uma seqüência vazia. Mesmo alguns bancos de dados relacionais (por exemplo, Oracle) não fazem distinção entre uma cadeia de comprimento zero e um NULL.
spencer7593
3
Isso é muito inteligente! Eu costumava escrever código inteligente, agora evito como uma praga. Agora eu quero que meu código tenha uma intenção clara, não apenas um comportamento correto. Meu conselho? Faça isso apenas se desejar confundir qualquer pessoa que precise oferecer suporte ao código / banco de dados. Por exemplo, no PHP, ambos ''e nullsão valores falsos.
CJ Dennis
1
@CJDennis Se você abstraiu sua camada de banco de dados por trás do padrão de repositório, não precisa se preocupar com a obscuridade desta solução.
prograhammer
17

O bit só é vantajoso em relação às várias opções de bytes (tinyint, enum, char (1)) se você tiver muitos campos booleanos. Um campo de bit ainda ocupa um byte completo. Campos de dois bits se encaixam no mesmo byte. Três, quatro, cinco, seis, sete, oito. Depois disso, eles começam a preencher o próximo byte. Por fim, as economias são tão pequenas que existem milhares de outras otimizações nas quais você deve se concentrar. A menos que você esteja lidando com uma quantidade enorme de dados, esses poucos bytes não serão suficientes. Se você estiver usando pouco com PHP, precisará digitar os valores entrando e saindo.

Thor
fonte
1
+1 para o comentário de conversão de tipo. Para adicionar isso ao trabalhar com linguagens de programação, evite usar técnicas de programação lenta em favor da consistência. Use operadores idênticos em vez de apenas iguais. No caso do PHP, se ($ var == "") for verdadeiro para 0, falso, nulo, indefinido e "". para testar todos os valores, geralmente é melhor usar if (true === vazio ($ var)), pois também evitará erros indefinidos. Você também deve validar o tipo de dados com o qual está trabalhando se (is_int ($ var) && $ var === 0) ou convertê-lo para forçá-lo a ser um tipo de dados específico (int) $ var para a tarefa.
fyrye
@ Thor é verdade para o MySQL da mesma forma que para o MSSQL? Estou migrando um novo aplicativo que ainda não foi produzido do MSSQL para o MySQL. Não estou usando PHP, mas convertendo C # para Java 8. Dado que Java é uma linguagem fortemente tipada, não estou preocupado com o tratamento de tipos ... apenas todos os sinalizadores de bits que se moveriam de um byte para até 8 sinalizadores para 1 byte a cada sinalizador, dado TINYINT (1). Você conhece alguma documentação sobre este tópico para o MySQL?
Zack Jannsen 02/02
1
@ Thor Fazendo uma pesquisa mais profunda, fica claro qual deve ser a resposta. A mudança acontece e vimos melhorias nesse manuseio. Conheça o seu idioma que estará na Camada de aplicativos / Camada de acesso a dados e conheça o suporte de suas bibliotecas. Atualmente, estou usando Java e o BIT (1) é a opção recomendada no momento para bibliotecas como Hybernate e uso de JDBC. Aqui está o URL [Veja a tabela 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen
12

Até o MySQL implementar um tipo de dados em bits, se o seu processamento for realmente pressionado por espaço e / ou tempo, como em transações de alto volume, crie um campo TINYINT chamado bit_flags para todas as suas variáveis ​​booleanas, mascare e altere o bit booleano em seu SQL inquerir.

Por exemplo, se o seu bit mais à esquerda representa o seu campo bool e os 7 bits à direita não representam nada, então o seu bit_flagscampo será igual a 128 (binário 10000000). Mascarar (ocultar) os sete bits mais à direita (usando o operador bit a bit &) e deslocar o oitavo bit em sete espaços para a direita, terminando com 00000001. Agora, o número inteiro (que, nesse caso, é 1) é o seu valor.

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

if bit_flags = 128 ==> 1 (true)
if bit_flags = 0 ==> 0 (false)

Você pode executar instruções como estas ao testar

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

etc.

Como você possui 8 bits, você tem potencialmente 8 variáveis ​​booleanas de um byte. Algum programador futuro invariavelmente usará os próximos sete bits, então você deve mascarar. Não apenas mude, ou você criará o inferno para si e para os outros no futuro. Certifique-se de que o MySQL faça sua máscara e mudança - isso será significativamente mais rápido do que a linguagem de script da web (PHP, ASP, etc.). Além disso, certifique-se de colocar um comentário no campo MySQL comment para seubit_flags campo.

Você encontrará esses sites úteis ao implementar este método:

Jonathan
fonte
7
Parece uma maneira terrível de ofuscar a intenção de futuros programadores. Claro que parece ser um monte de problemas para salvar 7 bytes (assumindo que você está usando todos os 8 bools nessa única mesa!)
sim
@ yep não há ofuscação! Escreva documentação e comentários do MySQL explicando cada campo na tabela (como a resposta menciona)! A estratégia sugerida de desmascaramento do MySQL parece sólida e armazenar até 16 campos booleanos diferentes com apenas algumas colunas é melhor do que ter 16 deles. Se for muito confuso usando manipulação de bits e você preferir usar sua linguagem de script da web para obter cada booleano, basta armazená-lo como um VARCHARe executar o procedimento de desmascaramento no código (você também não precisa limitá-lo a 8 campos) ...
CPHPython
O BITtipo existe. Veja dev.mysql.com/doc/refman/8.0/en/bit-type.html
dolmen
10

Eu me cansei de tentar obter zeros, NULLS e '' arredondar com precisão um loop de valores PHP, MySql e POST, então apenas uso 'Sim' e 'Não'.

Isso funciona perfeitamente e não precisa de tratamento especial que não seja óbvio e fácil de fazer.

Geoff Kendall
fonte
17
Se você realmente quisesse desperdiçar tanto espaço e comprometer o desempenho, poderia pelo menos executar o CHAR (1) com as opções Y e N.
ILikeTacos
3
Na maioria das situações do mundo real, há uma diferença real entre um "não" e uma mera ausência de informação. Por exemplo, convém marcar uma caixa de seleção por padrão se um usuário ainda não disse 'não'. Exatamente quanto espaço você acha que está economizando e quanto processa toda vez que precisa distinguir entre um falso e um NULL - se é que você consegue distinguir? Em um mundo de imagens armazenadas e vídeo digital, a parte de economia de espaço é absolutamente irrelevante, mas a clareza e o processamento reduzido são reais.
Geoff Kendall
8
Essa resposta não está errada porque funcionará e não é tão ruim quanto as pessoas dão crédito. Para a maioria dos projetos (por exemplo: tamanhos de tabela <1mil linhas), as diferenças de desempenho entre as soluções fornecidas serão negligenciadas. Não vou reclamar se minhas consultas retornarem em 7 vs 5 milissegundos ... Para ser justo, se suas tabelas estiverem crescendo em linhas de 10mil ou mais, essa provavelmente não é a solução preferida.
Brad
1
+1 de mim por usar o tipo de dados ENUM. Pessoalmente, prefiro esta notação: ENUM ('y', 'n'). É compacto (com apenas um byte de comprimento), intuitivo e de boa aparência como convenção no nível do aplicativo para todos os sinalizadores booleanos. Você pode usá-lo diretamente com os campos do formulário HTML. por exemplo, com PHP: <select name = "production"> <valor da opção = "y" <? = $ production === 'y'? 'selected = "selected"': ''? >> Sim </option> <opção value = "n" <? = $ production === 'n'? 'selected = "selected"': ''? >> Não </option> </select>
Enviado dia
2
Lol isso chamou minha atenção, mas eu tenho que dizer que @GeoffKendall está certo. Em muitos casos, não há necessidade de desempenho ideal e qualquer método que faça o trabalho para você é o método certo.
Madmenyo
6

Referindo-se a este link Tipo de dados booleano no Mysql , de acordo com o uso do aplicativo, se alguém quiser que apenas 0 ou 1 seja armazenado, o bit (1) é a melhor opção.

Vidz
fonte
6
É verdade que BIT(1)apenas permitirá que um b'0'ou b'1'valor seja armazenado. O maior problema com o BITtipo de dados é que várias bibliotecas clientes têm uma variedade de manipulação instável do tipo de dados. Faça o checkout do comportamento de várias ferramentas SQL (SQLyog, TOAD para MySQL, SQL Developer), ferramentas que fazem engenharia reversa de modelos de banco de dados e vários clientes, como JDBC, PHP, Perl DBI e, por uma boa medida, teste algumas estruturas ORM ( Hibernate, Mybatis, JPA). Em termos de facilidade de uso, compatibilidade de ferramenta / estrutura / suporte nativo, TINYINT(1)é o vencedor.
spencer7593
Sim. A conclusão depende da estrutura que está sendo considerada para o aplicativo. Por exemplo, PHP 's quadro Phalcon não lidar com tipo de dados Bit
Vidz
Para o registro, MyBatis suporta ambos BITe TINYINT. Consulte a classe JdbcType do MyBatis, mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/…
Lucky
1
@Vidz Dou-lhe mais um pela menção ao BIT (1), mas também gostaria de indicar aos desenvolvedores que estão lendo isso - Conheça o seu idioma que estará na Camada de Aplicação / Camada de Acesso a Dados e conheça o suporte de suas bibliotecas. Atualmente, estou usando Java e o BIT (1) é a opção recomendada no momento para bibliotecas como Hybernate e uso de JDBC. Aqui está o URL [Veja a tabela 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen
6

Como o MySQL (8.0.16) e o MariaDB (10.2.1) implementaram a restrição CHECK, agora eu usaria

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

Você só será capaz de loja 0, 1ou NULL, bem como os valores que podem ser convertidas para 0ou 1sem erros como '1', 0x00, b'1'ou TRUE/FALSE .

Se você não deseja permitir NULLs, adicione a NOT NULLopção

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

Observe que praticamente não há diferença se você usar TINYINT, TINYINT(1)ou TINYINT(123).

Se você deseja que seu esquema seja compatível com versões anteriores, também pode usar BOOLouBOOLEAN

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

db <> demo de violino

Paul Spiegel
fonte
what about enum (0, 1)
santiago arizti 08/08/19
3
@santiagoarizti ENUM(deve ser enum('0', '1')- nota: são strings) não é uma boa ideia. Há muitos problemas devido à forma como ele é armazenado internamente e como os valores não-string são tratados. Por exemplo. 0e FALSE não pode ser armazenado. 1e TRUEse tornar '0'. E 2se torna '1'.
Paul Spiegel
Melhor resposta ... para aqueles que usam o MySQL 8+ #
dolmen
2

Depois de ler as respostas aqui, decidi usar bit(1)e sim, é de alguma forma melhor no espaço / tempo, MAS depois de um tempo mudei de idéia e nunca mais o usarei. Isso complicou bastante meu desenvolvimento, ao usar instruções preparadas, bibliotecas etc. (php).

Desde então, eu sempre uso tinyint(1), parece bom o suficiente.

Lemures
fonte
3
Gostaria de explicar de que maneira isso complicou seu desenvolvimento?
precisa
@ChazyChaz espera true / false em vez de 1/0, ao contrário de outros dbs como o SQL Server. Às vezes, isso pode levar a situações estranhas nas quais você pensa que está definindo como verdade, mas na verdade não acontece.
maembe 31/05/19
0

Você pode usar o tipo de dados BOOL, BOOLEAN para armazenar valores booleanos.

Esses tipos são sinônimos para TINYINT (1)

No entanto, o tipo de dados BIT (1) faz mais sentido para armazenar um valor booleano (verdadeiro [1] ou falso [0]), mas é mais fácil trabalhar com TINYINT (1) quando você estiver produzindo os dados, consultando e assim por diante. e para obter interoperabilidade entre o MySQL e outros bancos de dados. Você também pode verificar esta resposta ou tópico .

O MySQL também converte os tipos de dados BOOL, BOOLEAN para TINYINT (1).

Além disso, leia a documentação

Premkumar chalmeti
fonte