Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

MySQL хранение двоичных чисел

#mysql #база_данных


Есть числа типа: 
111111111111111111111111111111111111111111111111111111111111111111111110111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
(168 символов).

Эти числа являются набором конфигурации по 168 пунктам, в виде TRUE(1) и FALSE(0). 

Как лучше его хранить чтобы и места не занимало и быстро считать записать в бд.?

В каком типе полей лучше хранить их?

UPD:
Корректирую задачу: набор из 168 цифр - это почасовые настройки на каждый день. Т.е.,
7х24=168. Требуется, в связке PHP+MySQL побитово этот конфиг записать в таблицу list->(поле)settings.  

  


Сейчас структура бд такая:  

`settings` tinyblob NOT NULL,


Занимает это дело соответсвенно [BLOB - 168 Байт]
Хотелось бы уместить в 168 бит(+-), т.к. будет много таких конфигов.
Как это реализовать это на PHP? 
    


Ответы

Ответ 1



Если это действительно набор настроек - то лучше хранить его в отдельной таблице, в формате "имя - флаг on/off". Полный набор настроек точно так же вычитывается одним запросом, а работать с ним будет легче в разы. Особенно если в какой-то момент вам придется настройку #40 удалить. Для обновленной версии вопроса - если это почасовые настройки - их стоит хранить в таблице вида Номер конфига | День недели | Час | On/Off И вам не придется работать с битами вообще. Можно спокойно загрузить весь конфиг, и в одно обращение узнать настройку для нужного часа нужного дня. Если волнуетесь за занимаемый объем - напрасно. Это около килобайта на один конфиг. Примерно 0.00000004$ при современных ценах на storage.

Ответ 2



Эм.. Хочется сохранить как 168 битовых колонок... Но как-то многовато. Возможно, стоит пересмотреть структуру базы? @Qwertiy как!? напиши пример пожалуйста. Что дописать в коде? Если нужно иметь blob, то записывай не строку, а массив байт. Конкретно для примера в вопросе этот массив такой: 255, 255, 192, 252, 15, 255, 255, 255, 255, 231, 255, 63, 255, 255, 255, 223, 239, 255, 1, 255, 255 Получил его так: `$d1='111111111111111111000000'; $d2='111111000000111111111111'; $d3='111111111111111111111111'; $d4='111001111111111100111111'; $d5='111111111111111111111111'; $d6='110111111110111111111111'; $d7='000000011111111111111111';` .match(/[01](?=[01'])/g).join("").match(/.{8}/g).map(function(s) { return parseInt(s, 2) })

Ответ 3



если нужно визуально читать тогда храните в HEX коде (char(42)) если чисто бинарный тогда и blob можно и char(21) UPD: если нужно использовать конкретный бит советую использовать BIGINT для 168 бит можно сделать 2 поле с BIGINT значениями (bigint = 8 byte = 64 bit) в MySQL есть готовые функции работы с битовыми операциями **BIT_COUNT()* - возврашает количество 1 в bigint & логическое AND ~ обратное значения | логическое OR ^ логическое XOR << здвиг в лево >> здвиг на право если нужен конкретный быть можно сделать так значения в базе 29 (... 0001 1101) а нам нужно последные 4 значения (1111 = 15) SELECT 29 & 15; -> 13 как видите 13 (1101) значит 2е значение не совпадает думаю так лучше UPD: увидел Update вопроса и пришлось обновить ответ если у вас уже имеется 7 дней по 24 часа тогда советую не оптимизировать через blob а использовать 7 переменный на каждый день. так даже легче по дням искать. где структура базы будет MEDIUMINT который имеет размер 24 bit почему выбрал эту структуру. Если нужно проверить, Вторник с 12:00 по 15:00 делаем так $day = 2; $d = bindec('00000000000111100000000'); $con=mysqli_connect("localhost","db_user","db_password","db"); mysqli_query($con,"SELECT d$day & $d FROM list WHERE d$day & $d > 0"); mysqli_close($con); если есть результат, значит в эти время по настройкам есть хотя бы ОДИН 1 а конкретно какие места 1 можно проверить из ответа запроса

Ответ 4



А не приходило в голову использовать стандартный функционал? На физическом уровне хранятся именно биты. https://dev.mysql.com/doc/refman/5.0/en/set.html пример запроса к значению одного SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0; Как вижу это я - каждый бит именуется отдельно, FIND_IN_SET позволяет получить по указанному "биту" значение - есть или нет. Ограничения - одним столбцом хранить не больше 64 значений, 255 на таблицу суммарно по столбцам. Вроде влезает.

Ответ 5



У меня реализована подобная схема. Только полный конфигурационный набор = 105 знаков... но суть остается та же. Таблица с такой структурой CREATE TABLE `web_settings` ( ... `settings1` bigint(20) NOT NULL, `settings2` bigint(20) NOT NULL, ... ) (подразумевается, что, если увеличится кол-во настроек, просто добавляется settings3...) Весь конфигурационный набор режется на куски по 60 знаков (array_chunk()) и загоняется в MySQL с переводом в десятиричную систему: UPDATE web_settings SET settings1=CONV(BINARY(".$chunk[0]."), 2, 10), settings2=CONV(BINARY(".$chunk[1]."), 2, 10) А чтобы достать данные из базы переводим обратно в двоичную SELECT BIN(settings1) as set1, BIN(settings2) as set2 FROM web_settings В PHP объединяем в один набор и загоняем в массив array_split и все. Насчет занимаемого места: bigint съедает 8 байт (https://dev.mysql.com/doc/refman/5.5/en/integer-types.html), т.е. у нас - 16... При наших объемах это приемлемо. Почему конфигурационный набор режется именно на 60 знаков? Ну как... В идеале было бы порезать по 64, но в этом случае полученное десятиричное число не влезет в bigint. Пришлось уменьшать - уменьшили до ближайшей круглой цифры. Из проблем, что мы столкнулись, могу назвать лишь то, что если есть какой-то конфигурационный параметр, у которого не два состояния, а три (yes/no/n.a.), то приходится хранить отдельно.. Хочу также оговориться, что система была реализована несколько лет назад. Может она и не идеальна, но тогда ru.so не было, чтобы спросить :):):):):)

Ответ 6



Если идти простым путем, то надо просто завести 7 полей типа BIT(24) в базе данных. Можно конечно завести 2 поля BIT(64) и одно BIT(40), но это уже вам решать. Именно благодаря такому типу полей (столбцов) БД запрос на добавление данных прост весьма Можно не пользоваться вариантом b'...', а писать прямо числа в базу (преобразовав строки в числа функцией bindec()). При считывании данных из базы, вы будете получать целое число и его надо преобразовать функцией php decbin() в двоичную строку. Это по моему самое очевидное и простое решение, потому что тут не надо использовать тип MEDIUMINT и прочие костыли.

Комментариев нет:

Отправить комментарий