Можно ли хранить 1 байтовый номер в Postgres? - PullRequest
21 голосов
/ 22 июня 2010

У меня есть 7 8-битных целочисленных значений на запись, которые я хочу сохранить в Postgres. Pg не предлагает однобайтового целочисленного типа, SMALLINT или 2 байта, являющегося самым маленьким целочисленным типом данных. Могу ли я в любом случае хранить свои 7 8-битных чисел и экономить место?

Будет ли тип массива с массивом из 7 элементов более компактным? Или я должен сделать двоичное представление моих 7 чисел (например, используя pack в Perl) и сохранить их в одном поле bytea?

Любые другие предложения?

Ответы [ 7 ]

17 голосов
/ 22 июня 2010

Учитывая, что издержки для любой строки в PostgreSQL составляют 23 байта (HeapTupleHeaderData), если вы действительно заботитесь о небольших объемах пространства, вы, вероятно, выбрали неправильный способ хранения ваших данных.

Несмотря на это, поскольку все более сложные типы имеют свои собственные служебные данные (например, bytea добавляет четыре байта служебных данных, например, битовые строки с 5 по 8), единственный способ выполнить то, что вы ищете, это использовать bigint.(8 байт), численно сдвигая каждое значение и объединяя результат.Вы можете сделать это, используя операции с битовой строкой , чтобы упростить код - вычислите как битовую строку, затем приведите к bigint перед сохранением - или просто умножьте / сложите вручную, если хотите, чтобы скорость была лучше.Например, вот как вы храните два байта вместе в двухбайтовой структуре и затем возвращаете их снова:

int2 = 256 * byte1 + byte2
byte1 = int2 / 256
byte2 = int2 % 256

Вы можете распространить ту же идею на хранение 7 из них таким образом.Затраты на поиск по-прежнему будут ужасными, но вы фактически сэкономите место в процессе.Но не очень по отношению только к заголовку строки.

4 голосов
/ 25 октября 2011

Существует тип pg_catalog.char (другое обозначение - "char"), который использует только 1 байт для хранения своего значения.

select pg_column_size( 'A' );
pg_column_size
----------------
              2
(1 row)

select pg_column_size( 'A'::"char" );
pg_column_size
----------------
              1
(1 row)
2 голосов
/ 22 июня 2010

Будете ли вы когда-нибудь искать записи, используя эти значения?

Если да - используйте обычные типы данных, такие как int4 (или даже int8, если вы используете 64-битную архитектуру).

Если нет - сначала спросите себя - какой смысл хранить эти значения в Pg? Вы можете использовать bytea (сложный ввод / вывод) или цепочки битов (даже более сложный ввод / вывод), но какой в ​​этом смысл? Сколько миллиардов записей у вас будет? Вы действительно проверяли, что меньший тип данных использует меньше места (подсказка: это не так, проверьте его - есть проблемы с выравниванием данных)? Вы работаете под впечатлением, что меньший тип данных быстрее (это не так. На самом деле более сложно сравнивать два значения int2, чем два значения int4 в 32-разрядной архитектуре).

1 голос
/ 19 марта 2018

"char"

Это однобайтовый тип в PostgreSQL, который соответствует диапазону -1212127.Начиная с документов,

Тип "char" (обратите внимание на кавычки) отличается от char(1) тем, что использует только один байт памяти. Он используется внутри системных каталогов как упрощенный тип перечисления.

Вы можете сместить это в сторону [-128,127], вычтя 128 из любого входа в диапазоне [0-255] передвы записываете в базу данных и добавляете ее обратно в вывод при чтении из базы.

-- works
SELECT (-128)::"char", 127::"char";

-- generates out of range
SELECT (-128)::"char";
SELECT 128::"char";

-- Shifts to unsigned range.
-- If you're going to be using "char"
-- review the results of this query!
SELECT
  x::int AS "inputUnsigned",
  chr(x) AS "extendedASCII",
  -- this is the "char" types representation for that input.
  signed::"char" AS "charRepresentation",

  signed     AS "inputUnsignedToSigned",
  signed+128 AS "inputUnsignedToSignedToUnsigned"
FROM generate_series(1,255) AS gs(x)
-- Here we map the input in the range of [0,255] to [-128,127]
CROSS JOIN LATERAL ( VALUES (x::int-128) )
  AS v(signed);

Небольшая выдержка из вывода

 inputUnsigned | extendedASCII | charRepresentation | inputUnsignedToSigned | inputUnsignedToSignedToUnsigned 
---------------+---------------+--------------------+-----------------------+---------------------------------
....
           190 | ¾             | >                  |                    62 |                             190
           191 | ¿             | ?                  |                    63 |                             191
           192 | À             | @                  |                    64 |                             192
           193 | Á             | A                  |                    65 |                             193
           194 | Â             | B                  |                    66 |                             194
           195 | Ã             | C                  |                    67 |                             195
           196 | Ä             | D                  |                    68 |                             196
...

Мы используем generate_series(1,255) только потому, что chr(0) выбрасывает, потому что вы не можете сгенерировать или вывести ASCII NUL (PostgreSQL использует cstrings)

pguint Extension

Pguint является расширением, которое обеспечивает два однобайтовых представления,

  • int1 (со знаком)
  • uint1 (без знака)
1 голос
/ 21 февраля 2013

Я не проверял их сам, но есть расширения для этого;например, http://pgxn.org/dist/tinyint/.

1 голос
/ 16 марта 2011

Сначала вы спрашивали о 7, а теперь 6 байтов. Шесть 8-битных значений точно соответствуют размеру MAC-адреса и встроенному в PostgreSQL типу macaddr. Вы можете вставить эти байты, используя синтаксис MAC f.i. А1-В2-С3-Д4-Е5-F6.

1 голос
/ 22 июня 2010

Вы захотите взглянуть на тип данных bytea, на который ссылаются здесь: http://www.postgresql.org/docs/8.4/interactive/datatype-binary.html

Также существуют типы данных битовых строк: http://www.postgresql.org/docs/8.4/interactive/datatype-bit.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...