Какой тип данных MySQL использовать для хранения логических значений

1208

Поскольку в MySQL, похоже, нет какого-либо «логического» типа данных, какой тип данных вы «используете» для хранения истинной / ложной информации в MySQL?

Особенно в контексте написания и чтения из / в сценарий PHP.

Со временем я использовал и видел несколько подходов:

  • tinyint, поля varchar, содержащие значения 0/1,
  • поля varchar, содержащие строки '0' / '1' или 'true' / 'false'
  • и, наконец, перечислить поля, содержащие две опции 'true' / 'false'.

Ничто из вышеперечисленного не кажется оптимальным. Я предпочитаю вариант tinyint 0/1, так как автоматическое преобразование типов в PHP дает мне логические значения довольно просто.

Так какой тип данных вы используете? Есть ли тип, разработанный для логических значений, который я пропустил? Видите ли вы какие-либо преимущества / недостатки при использовании того или иного типа?

Питер Мортенсен
источник
217
Любой, кто читает старые ответы на этот вопрос, должен понимать, что MySQL добавил немного типа данных в версии 5. Используйте эту информацию, как можете. dev.mysql.com/doc/refman/5.0/ru/bit-type.html
smp7d
7
для текущей версии MYSQL доступен логический тип - dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html проверьте это. согласно этому значению ноль считается ложным
DevT
7
bit(1)бит ** для импорта в Excel. Переход на tinyint(1)работы.
Сис Тиммерман
8
теперь у нас логическое значение через 5 лет
V-SHY

Ответы:

1232

Для MySQL 5.0.3 и выше вы можете использовать BIT. В руководстве сказано:

Начиная с MySQL 5.0.3, тип данных BIT используется для хранения значений битовых полей. Тип BIT (M) позволяет хранить M-битные значения. М может варьироваться от 1 до 64.

В противном случае, согласно руководству MySQL, вы можете использовать bool и boolean, которые на данный момент являются псевдонимами tinyint (1):

Bool, Boolean: Эти типы являются синонимами для TINYINT (1). Нулевое значение считается ложным. Ненулевые значения считаются истинными.

MySQL также заявляет, что:

Мы намерены реализовать полную обработку булевых типов в соответствии со стандартным SQL в будущем выпуске MySQL.

Ссылки: http://dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html

Markus
источник
11
Да, я выбрал бы это или CHAR (1) и сохранял бы «Y» / «N» или «T» / «F» и т. Д. В зависимости от контекста. Преимущество использования целочисленного типа малого размера состоит в том, что вы получаете максимальную переносимость между RDBMS-es
Роланд Буман
36
Переход на char, по крайней мере в PHP, приведет к большему количеству кода, !$booleanкоторый никогда не будет оцениваться должным образом без дальнейшей обработки.
Мягкий пух
10
@Pecerier Ничего, что ты не мог бы гуглить сам, но хорошо, я укушу. Прежде всего, пожалуйста, посмотрите на data0type.h. Обратите внимание, что innodb изначально не определяет тип BIT. Если бы он обрабатывал BIT-поля так, как вы описываете, мы наверняка нашли бы там какой-то намек на его существование. Во-вторых, прочитайте mysqlperformanceblog.com/2008/04/23/… . И не стесняйтесь сообщить нам, какие замечательные клиенты MySQL в "marktetplace" хорошо работают с полями BIT. Они пригодятся тем, кто пропустил эту статью, без сомнения.
Роланд Боуман
9
Когда я делаю выбор из стандартной командной строки клиента mysql, битовые поля отображаются полностью пустыми. Из-за этого я предпочитаю TINYINT (1).
Пользователь
8
@MikePurcell Я не хочу спрашивать, но зачем вам auto_incrementстолбец, представляющий логическое значение?
Крис Хейс
248

BOOLи BOOLEANявляются синонимами TINYINT(1). Ноль есть false, все остальное есть true. Больше информации здесь .

Филип Мортон
источник
7
Это (1)не что иное, как определение того, как отображается значение. Если вы помните о размере хранилища, то BITвместо этого вы захотите его использовать
JamesHalsall
35
@JamesHalsall: На самом деле, BIT(1)и TINYINT(1)оба будут использовать один байт памяти. Вплоть до MySQL 5.0.3 BITфактически был синонимом TINYINT. Более поздние версии MySQL изменили реализацию BIT. Но даже с изменением реализации, все еще нет никакого преимущества "размера хранилища" для BITтипа данных (по крайней мере, с InnoDB и MyISAM; другие механизмы хранения, например NDB, могут иметь некоторую оптимизацию хранения для нескольких объявлений столбцов BIT.) Большая проблема заключается в том, что некоторый клиент библиотеки не распознают или не обрабатывают должным образом возвращаемые BITстолбцы типов данных. А TINYINTработает лучше.
spencer7593
5
В руководстве по MySQL 5.0 четко указано, что логическое значение равно 1 или 0. Фраза «все остальное есть true» не соответствует действительности.
Уолтер
7
@ Вальтер: На самом деле это своего рода правда, объяснение несколько отсутствует. Вкратце, в логическом контексте выражение может иметь значение NULL, FALSE или TRUE. В операторе MySQL выражение, вычисленное в логическом контексте, сначала оценивается как целое число (десятичные значения и значения с плавающей запятой округляются, строки преобразуются обычным странным способом, которым MySQL преобразует строки в целое число). NULL, очевидно, NULL (ни ИСТИНА, ни ЛОЖЬ). Целочисленное значение 0 обрабатывается как FALSE, а любое другое целочисленное значение (1, 2, -7 и т. Д.) Оценивается как TRUE. Для совместимости мы подражаем этой логике / обработке логического значения
TINYINT
4
@Walter: это легко проверить, например SELECT 'foo' AS bar FROM dual WHERE -7. Выражение -7 вычисляется в логическом контексте, и запрос возвращает строку. Мы можем проверить с 0 или любым выражением, которое оценивается как целочисленное значение 0, и строка не возвращается. Если выражение в предложении WHERE оценивается как любое ненулевое целочисленное значение, отличное от нуля, выражение имеет значение ИСТИНА. (Я полагаю, что десятичные значения и значения с плавающей запятой округляются до целого числа, например, 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.

(Этот метод описан в статье «Высокопроизводительный MySQL: оптимизация, резервное копирование, репликация и многое другое» Джона Уоррена Ленца, Барона Шварца и Арьена Ленца.)

RS
источник
3
модный трюк! это полезно, если вы работаете с MySQL <5 и, возможно, даже с меньшими затратами, чем BIT, однако, пытаясь соответствовать соглашению и немного меньше затрат на вычисления (логика против точного значения), я бы сказал, что BIT - лучший путь.
Zamnuts
59
Может быть «быстро», но это запутывает данные так, что любой новый разработчик не будет знать, что означает этот столбец.
Рихтгофен
5
Это использует то же количество байтов, что и BIT (1)
ЕГО Аляска
25
Удачи в получении ORM, чтобы сопоставить это с этим.
Крейг Лабенс,
4
Я согласен с @Richthofen и мне трудно представить ситуацию, в которой я бы когда-либо выступал за использование этого решения. Однако, если он будет использоваться, то указание в качестве определения COMMENTв столбце, которое NULLуказывает на ложь и ''указывает на истину, может пойти очень маленьким путем, помогающим пониманию будущего.
eggyal
34

Если вы используете тип BOOLEAN, это псевдоним TINYINT (1). Это лучше всего, если вы хотите использовать стандартизированный SQL и не обращать внимания на то, что поле может содержать значение вне диапазона (в основном все, что не равно 0, будет «истинным»).

ENUM («False», «True») позволит вам использовать строки в вашем SQL, а MySQL будет хранить поле внутри как целое число, где «False» = 0 и «True» = 1 в зависимости от порядка, указанного Enum ,

В MySQL 5+ вы можете использовать поле BIT (1) для обозначения 1-битного числового типа. Я не верю, что на самом деле это занимает меньше места в хранилище, но опять же позволяет ограничить возможные значения до 1 или 0.

Все вышеперечисленное будет использовать примерно одинаковый объем памяти, поэтому лучше выбрать тот, с которым вам проще всего работать.

Кьяран МакНалти
источник
8
Ваше замечание относительно ENUM неверно: попробуйте CAST (yourenumcol AS UNSIGNED), и вы заметите, что False будет 1, а True будет 2. Другая проблема с ENUM состоит в том, что слишком легко вставить '' (пустая строка ) Я бы не рекомендовал использовать это.
Роланд Буман
4
По моему опыту, использование поля BIT (1) из кода PHP было немного хлопотно. TINYINT (1) был намного проще и создавал более читаемый код.
М-Перор
1
@ M-Peror - «использование поля BIT (1) из кода PHP было немного хлопотно» ... не каламбур. :) Но да, я согласен. Я помню, что TINYINT (1) тоже был проще ... просто не помню почему. У кого-нибудь еще есть мысли по этому поводу? BIT (1) кажется более приятным на первый взгляд, потому что вы можете ограничиться 0 или 1. Я думаю, что BIT иногда интерпретировали как двоичные данные (в зависимости от языка программирования и драйвера / библиотеки); в то время как TINYINT рассматривался больше как число.
BMiner
2
@BMiner - ха-ха, это было действительно непреднамеренно, я этого не заметил :) Но действительно, если я правильно помню, битовое поле интерпретировалось как нечто двоичное, тогда как tinyint было легче воспринимать как число, и поэтому легче использовать в (логическом) выражении.
М-Перор
34

На этот вопрос ответили, но я решил добавить свои 0,02 доллара. Я часто использую CHAR(0), где '' == true and NULL == false.

Из документов MySQL :

CHAR(0)Это также неплохо, когда вам нужен столбец, который может принимать только два значения: столбец, который определен как, CHAR(0) NULLзанимает только один бит и может принимать только значения NULLи ''(пустую строку).

мистифицировать
источник
16
мм, это похоже на проблемы, если вы, как я. Я имею в виду, что в зависимости от языка может быть слишком просто не заметить разницу между NULL и '' (например, PHP).
Ролан Боуман
3
С точки зрения экономии места (количество байтов, используемых для представления логического значения), этот подход является явным победителем. Это сохраняет байт над TINYINT. Недостатком (как отмечают некоторые комментарии) является то, что некоторые клиенты могут испытывать трудности при различении NULL и пустой строки. Даже некоторые реляционные базы данных (например, Oracle) не различают строку нулевой длины и NULL.
spencer7593
3
Это очень умно! Раньше я писал умный код, теперь я избегаю его, как чумы. Теперь я хочу, чтобы мой код имел кристально чистое намерение, а не только правильное поведение. Мой совет? Делайте это только если вы хотите сбить с толку тех, кто поддерживает код / ​​базу данных. Например, в PHP оба ''и nullявляются ложными значениями.
CJ Деннис
1
@CJDennis Если вы абстрагировали слой своей базы данных за шаблоном репозитория, вам не нужно беспокоиться о неясности этого решения.
программист
18

Я использую TINYINT (1) для хранения логических значений в Mysql.

Я не знаю, есть ли какое-то преимущество, чтобы использовать это ... Но если я не ошибаюсь, mysql может хранить логическое значение (BOOL) и хранить его как tinyint (1)

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

Фред
источник
17

Бит имеет преимущество перед различными опциями байтов (tinyint, enum, char (1)), если у вас много логических полей. Одно битовое поле все еще занимает полный байт. Два битовых поля вписываются в один и тот же байт. Три, четыре, пять, шесть, семь, восемь. После чего они начинают заполнять следующий байт. В конечном итоге экономия настолько мала, что вы должны сосредоточиться на тысячах других оптимизаций. Если вы не имеете дело с огромным количеством данных, эти несколько байтов не будут складываться во много. Если вы используете бит с PHP, вам нужно ввести значения, входящие и выходящие.

Тор
источник
1
+1 для комментария по типизации. Чтобы добавить к этому при работе с языками программирования, избегайте использования ленивых методов программирования в пользу последовательности. Используйте одинаковые операторы вместо просто равных. В случае PHP if ($ var == "") будет true для 0, false, null, undefined и "". для проверки всех значений часто лучше использовать if (true === empty ($ var)), поскольку это также позволит избежать неопределенных ошибок. Вам также следует проверить тип данных, с которым вы работаете if (is_int ($ var) && $ var === 0), или типизировать его, чтобы он стал конкретным типом данных (int) $ var для задачи.
фырье
@ Это правда для MySQL в той же степени, что и для MSSQL? Я перевожу новое приложение, которое еще не запущено в производство, с MSSQL на MySQL. Я не использую PHP, а скорее преобразую C # в Java 8. Учитывая, что Java является строго типизированным языком, я не беспокоюсь об обработке типов ... просто все битовые флаги, которые будут перемещаться от одного байта до 8 флагов к 1 байт каждого флага, заданного TINYINT (1). Знаете ли вы какую-либо документацию по этой теме для MySQL?
Зак Яннсен
1
@Thor Проведя более глубокое исследование, ясно, каким должен быть ответ. Изменения происходят, и мы увидели улучшения в этой обработке. Знайте свой язык, который будет на уровне приложений / уровне доступа к данным, и знайте, что ваши библиотеки поддерживают. В настоящее время я использую Java, и в настоящее время рекомендуется использовать BIT (1) для таких библиотек, как Hybernate и JDBC. Вот URL [см. Таблицу 5.2]: dev.mysql.com/doc/connector-j/en/…
Зак Яннсен,
12

До тех пор, пока MySQL не реализует битовый тип данных, если ваша обработка действительно ограничена пространством и / или временем, например, при транзакциях большого объема, создайте поле TINYINT, вызываемое bit_flagsдля всех ваших логических переменных, и маскируйте и сдвигайте нужный логический бит в своем 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)

Вы можете запускать такие заявления во время тестирования

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

и т.п.

Поскольку у вас есть 8 битов, у вас есть потенциально 8 логических переменных из одного байта. Некоторые будущие программисты всегда будут использовать следующие семь битов, поэтому вы должны замаскировать. Не просто сдвиньтесь, иначе вы создадите ад для себя и других в будущем. Убедитесь, что MySQL выполняет маскирование и сдвиг - это будет значительно быстрее, чем это делает язык веб-сценариев (PHP, ASP и т. Д.). Кроме того, убедитесь, что вы поместили комментарий в поле комментариев MySQL для своего bit_flagsполя.

Вы найдете эти сайты полезными при реализации этого метода:

Джонатан
источник
7
Это похоже на ужасный способ запутать намерения будущих программистов. Конечно, кажется, что много проблем с сохранением 7 байтов (при условии, что вы используете все 8 bools в этой единственной таблице!)
да,
@ да нет никакого запутывания вообще! Напишите документацию и комментарии MySQL, объясняющие каждое поле в таблице (как упоминается в ответе)! Предлагаемая стратегия демаскирования MySQL выглядит солидно, и лучше хранить до 16 различных логических полей с парой столбцов, чем иметь 16 из них. Если использование битовых манипуляций слишком сложно, и вы предпочитаете использовать свой язык веб-сценариев для получения каждого логического значения, просто сохраните его как a VARCHARи выполните процедуру демаскирования в коде (вам также не нужно ограничивать его 8 полями) ...
CPHPython
BITТипа существует. См. Dev.mysql.com/doc/refman/8.0/en/bit-type.html
дольмен
10

Я сыт по горло попытками получить нули, NULLS и «точно» в цикле значений PHP, MySql и POST, поэтому я просто использую «Да» и «Нет».

Это работает безупречно и не требует особой обработки, которая не очевидна и проста в исполнении.

Джефф Кендалл
источник
17
Если вы действительно хотите потратить столько места и поставить под угрозу производительность, вы могли бы по крайней мере сделать CHAR (1) с опциями Y и N.
ILikeTacos
3
В большинстве реальных ситуаций существует реальная разница между «нет» и просто отсутствием информации. Например, вы можете установить флажок по умолчанию, если пользователь еще не сказал «нет». Как вы думаете, сколько именно места вы экономите, и сколько обработки вы выполняете каждый раз, когда вам нужно различать ложное и NULL - если вы вообще МОЖЕТЕ различать? В мире сохраненных изображений и цифрового видео один или два бита экономии пространства совершенно не важны, но ясность и уменьшенная обработка реальны.
Джефф Кендалл,
8
Этот ответ не является неправильным, потому что он будет работать, и он не так плох, как люди считают, что это правильно. Для большинства проектов (то есть: размеры таблиц <1 мил строк) Различия в производительности между предоставленными решениями будут незначительными. Я не буду жаловаться, если мои запросы возвращаются через 7 против 5 миллисекунд ... Если быть честным, хотя, если ваши таблицы растут в 10 миллионов строк или более, это, вероятно, не является предпочтительным решением.
Брэд
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
2
Lol это поймал мой взгляд, но я должен сказать, что @ GeoffKendall прав. В большинстве случаев нет необходимости в оптимальной производительности, и какой бы метод ни выполнял работу для вас, это правильный метод.
Madmenyo
6

Ссылаясь на эту ссылку, Boolean datatype в Mysql , в соответствии с использованием приложения, если кто-то хочет сохранить только 0 или 1, бит (1) является лучшим выбором.

Vidz
источник
6
Это правда, что BIT(1)только позволит b'0'или b'1'значение будет сохранено. Самая большая проблема с BITтипом данных заключается в том, что различные клиентские библиотеки имеют различные возможности обработки этого типа данных. Изучите поведение в различных инструментах SQL (SQLyog, TOAD for MySQL, SQL Developer), инструментах, которые "восстанавливают" модели баз данных, а также на различных клиентах, таких как JDBC, PHP, Perl DBI, и для хорошей проверки протестируйте несколько сред ORM ( Hibernate, Mybatis, JPA). С точки зрения простоты использования, инструментальная / совместимая среда / нативная поддержка TINYINT(1)- явный победитель.
spencer7593
Да. Завершение зависит от структуры, рассматриваемой для приложения. Например, PHP-инфраструктура Phalcon не обрабатывает битовый тип данных
Vidz,
Для записи, MyBatis поддерживает BITи TINYINT. Обратитесь к классу MyBatis JdbcType, mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/…
Lucky
1
@Vidz Я даю вам плюс один за упоминание BIT (1), но также хотел бы указать разработчикам, читающим это: знайте свой язык, который будет на уровне приложений / уровне доступа к данным, и знайте, что ваши библиотеки поддерживают. В настоящее время я использую Java, и в настоящее время рекомендуется использовать BIT (1) для таких библиотек, как Hybernate и JDBC. Вот URL [см. Таблицу 5.2]: dev.mysql.com/doc/connector-j/en/…
Зак Яннсен,
6

Поскольку MySQL (8.0.16) и MariaDB (10.2.1) реализовали ограничение CHECK, я бы сейчас использовал

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

Вы сможете только в магазине 0, 1или NULL, а также значения , которые могут быть преобразованы в 0или 1без ошибок , как '1', 0x00, b'1'или TRUE/FALSE .

Если вы не хотите разрешать NULL, добавьте NOT NULLопцию

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

Обратите внимание, что практически нет разницы, если вы используете TINYINT, TINYINT(1)илиTINYINT(123) .

Если вы хотите, чтобы ваша схема была совместимой вверх, вы также можете использовать BOOLилиBOOLEAN

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

ДБ <> Fiddle Demo

Пол Шпигель
источник
что насчет enum (0, 1)
santiago arizti
3
@santiagoarizti ENUM(должно быть, enum('0', '1')обратите внимание: это строки) не очень хорошая идея. Есть слишком много вопросов , из - за того , как она хранится внутри, и как нестроковые значения обрабатываются. Например. 0и FALSE не может быть сохранен. 1и TRUEстать '0'. И 2становится '1'.
Пол Шпигель
Лучший ответ ... для тех, кто использует MySQL 8+
дольмен
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).

Далее читайте документацию

Премкумар чалмети
источник