Как хранить 60 булевых элементов в базе данных MySQL?

Я создаю мобильное приложение. Я использую PHP и MySQL для написания бэкэнд - API REST.

Если мне нужно хранить около 50-60 булевых значений в таблице под названием "Отчеты" (пользователи должны проверять вещи в форме), в моем мобильном приложении я храню значения (0/1) в простом массиве. В моей таблице MySql я должен создать другой столбец для каждого логического значения или достаточно, если я просто использую строку или Int, чтобы сохранить ее как "число", например "110101110110111..."?

Я получаю и помещаю данные в JSON.

ОБНОВЛЕНИЕ 1: все, что мне нужно сделать, это проверить, все ли 1, если один из них равен 0, то это "проблема". Через 2 года эта таблица будет содержать около 15 000-20 000 строк, она должна быть очень быстрой и максимально экономичной.

ОБНОВЛЕНИЕ 2: С точки зрения скорости, какое решение быстрее? Создание отдельных столбцов и сохранение их в виде строки/двоичного типа. Что делать, если я должен проверить, какие из них - 0? Является ли это отличным решением, если я сохраню его как "число" в одном столбце, и если он не "111..111", то отправьте его в мобильное приложение как JSON, где я проанализирую значение и проанализирую его на пользовательском устройстве? Скажем, мне приходится иметь дело с 50K строками.

Спасибо заранее.

Ответ 1

Отдельный столбец для каждого значения более гибкий, когда дело доходит до поиска.

Отдельная таблица ключей/значений более гибкая, если разные строки имеют разные коллекции логических значений.

И, если

  • ваш список булевых значений более или менее статичен.
  • все ваши строки имеют все эти логические значения
  • ваш критически важный для вас поиск - это поиск строк, в которых любое из значений ложно.

тогда использование текстовых строк, таких как "1001010010" и т.д., является хорошим способом их хранения. Вы можете выполнить поиск следующим образом

 WHERE flags <> '11111111'

чтобы найти нужные вам строки.

Вы можете использовать столбец BINARY с одним битом на флаг. Но ваш стол будет проще использовать для случайных запросов и проверки глазного яблока, если вы используете текст. Экономия пространства при использовании BINARY вместо CHAR не будет существенной, пока вы не начнете хранить много миллионов строк.

изменить. Надо сказать: каждый раз, когда я создавал что-то подобное с массивами логических атрибутов, позже я был разочарован тем, насколько он неликвиден. Например, предположим, что это был каталог лампочек. На рубеже тысячелетий булевы флаги могли быть такими, как

screw base
halogen
mercury vapor
low voltage

Затем меняются вещи, и мне нужно больше логических флагов, например,

LED
CFL 
dimmable
Energy Star

и т.д.. Внезапно мои типы данных не достаточно велики, чтобы удерживать то, что мне нужно для их хранения. Когда я писал, что "ваш список логических значений более или менее статичен", я имел в виду, что вы не можете рассчитывать на изменение характеристик лампочек в течение всего срока службы вашего приложения.

Таким образом, отдельная таблица атрибутов может быть лучшим решением. Он будет иметь следующие столбцы:

   item_id           fk to item table         -- pk
   attribute_id      attribute identifier     -- pk
   attribute_value   

Это в конечном счете гибкое. Вы можете просто добавить новые флаги. Вы можете добавлять их к существующим элементам или к новым элементам в любое время в течение всей жизни вашего приложения. И каждый элемент не нуждается в одном наборе флагов. Вы можете написать "какие предметы имеют ложные атрибуты?" запрос выглядит следующим образом:

 SELECT DISTINCT item_id FROM attribute_table WHERE attribute_value = 0

Но вы должны быть осторожны, потому что запрос "какие элементы имеют отсутствующие атрибуты" намного сложнее написать.

Ответ 2

Для вашей конкретной цели, когда любой флаг нуля - это проблема (исключение), и большая часть записей (например, 99%) будет "1111... 1111", я не вижу причин для их хранения. Я бы предпочел создать отдельную таблицу, в которой хранятся только флаги без отметки. Таблица может выглядеть так: uncheked_flags (user_id, flag_id). В другой таблице вы сохраняете свои определения флагов: flags (flag_id, flag_name, flag_description).

Тогда ваш отчет будет таким же простым, как SELECT * FROM unchecked_flags.

Обновить - возможные определения таблиц:

CREATE TABLE `flags` (
    `flag_id` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
    `flag_name` VARCHAR(63) NOT NULL,
    `flag_description` TEXT NOT NULL,
    PRIMARY KEY (`flag_id`),
    UNIQUE INDEX `flag_name` (`flag_name`)
) ENGINE=InnoDB;

CREATE TABLE `uncheked_flags` (
    `user_id` MEDIUMINT(8) UNSIGNED NOT NULL,
    `flag_id` TINYINT(3) UNSIGNED NOT NULL,
    PRIMARY KEY (`user_id`, `flag_id`),
    INDEX `flag_id` (`flag_id`),
    CONSTRAINT `FK_uncheked_flags_flags` FOREIGN KEY (`flag_id`) REFERENCES `flags` (`flag_id`),
    CONSTRAINT `FK_uncheked_flags_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB;

Ответ 3

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

Если вы просто ищете HIGH-VALUES 0xFFF.... то определенно растровое изображение, это решает вашу проблему с мощностью (за обновление OP). Это не похоже на то, что вы проверяете паритет... Однако дерево будет сильно искажено до ВЫСОКИХ ЦЕННОСТЕЙ, если это нормально, и может создать горячую точку, подверженную node расщеплению на вставки.

Бит-сопоставление и использование побитовых масок оператора сэкономит место, но их нужно будет выровнять по байту, поэтому может быть неиспользуемый "наконечник" (возможно, для будущих полей), поэтому маска должна иметь поддерживаемую длину или поле заполнено 1s.

Это также добавит сложности вашей архитектуре, что может потребовать индивидуального кодирования, стандартных стандартов.

Вам нужно выполнить анализ важности любого поиска (обычно вы не можете ожидать поиска всего или даже любого из дискретных полей).

Это очень распространенная стратегия денормализации данных, а также настройка запроса обслуживания для конкретных клиентов. (Там, где некоторые reponses более толстые, чем другие для одной и той же транзакции).