2010-06-22 19 views
18

Tengo 7 valores enteros de 8 bits por registro que quiero almacenar en Postgres. Pg no ofrece un tipo entero de un byte, SMALLINT o 2 bytes, que es el tipo de datos entero más pequeño. ¿De todos modos puedo almacenar mis 7 números de 8 bits y ahorrar espacio?¿Es posible almacenar un número de 1 byte en Postgres?

¿Sería más compacto un tipo de matriz con una matriz de 7 elementos? O bien, ¿debería hacer una representación binaria de mis 7 números (por ejemplo, usando un paquete en Perl) y almacenar eso en un solo campo bytea?

¿Alguna otra sugerencia?

Respuesta

17

Dado que la sobrecarga de cualquier fila en PostgreSQL es 23 bytes (HeapTupleHeaderData), si realmente le interesan las pequeñas cantidades de espacio esto probablemente haya elegido la forma incorrecta de almacenar sus datos.

Independientemente de que todos los tipos más complicados tengan sus propios gastos generales (bytea agrega cuatro bytes de sobrecarga, por ejemplo, cadenas de bits 5 a 8), la única manera de lograr lo que estás buscando es usar un bigint (8 bytes), desplazando numéricamente cada valor y OR-ing juntos el resultado. Puede hacer esto usando el bit string operations para hacer que el código sea más fácil: calcule como una cadena de bits, luego conviértalo en letra grande antes de almacenarlo, o simplemente multiplique/agregue manualmente si desea que la velocidad sea mejor. Por ejemplo, aquí es cómo es posible almacenar dos bytes juntos en una estructura de dos bytes y luego recuperarlas:

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

se puede extender la misma idea en el almacenamiento de 7 de ellos de esa manera. La sobrecarga de recuperación aún será terrible, pero habrá ahorrado espacio en el proceso. Pero no mucho en relación con solo el encabezado de la fila.

+3

cada fila tiene enteros de 6 x 1 byte (?), Enteros de 3 x 2 bytes (SMALLINT) y enteros de 2 x 4 bytes (INT). Eso es un total de 20 bytes por fila, más la sobrecarga de Pg. Como Pg solo proporciona SMALLINT como el valor más pequeño, mis valores de 6 1 byte tomarán 12 bytes. Estoy buscando una posible alternativa para estos. Un ahorro de 6 bytes por 120 mil millones de filas es de aproximadamente 670 GB (si mi cálculo es correcto). Dicho esto, necesito sacar estos valores individualmente, por lo que podría pagar el precio en velocidad de recuperación. Necesito equilibrar los dos. 0.7 TB no es una gran cantidad de espacio en el esquema más grande de las cosas. – punkish

2

¿Alguna vez las operaciones de búsqueda de registros utilizando estos valores?

En caso afirmativo, utilice tipos de datos normales como int4 (o incluso int8 si tiene arquitectura de 64 bits).

Si no, primero pregúntese: ¿cuál es el sentido de almacenar estos valores en Pg? Puedes usar bytea (complicada E/S), o bitstrings (incluso E/S más complicadas), pero ¿cuál es el punto? ¿Cuántos billones de registros va a tener? ¿Realmente revisaste que el tipo de datos más pequeño usa menos espacio (pista: no lo hace, compruébalo, hay problemas de alineación de datos)? ¿Está trabajando con la impresión de que el tipo de datos más pequeño es más rápido (no lo es)? En realidad es más complejo comparar dos valores int2 que dos valores int4 en la arquitectura de 32 bits).

+1

tiene preguntas válidas, algunas de las cuales podría haber evitado proporcionando más información. Tengo 6 valores de 8 bits y esperaba 120 mil millones de filas. Por lo tanto, el deseo de conservar el espacio tanto como sea posible. – punkish

+4

Realmente ahorra espacio para almacenar int2 vs int4. Probé en 8.4 y almacené 7 x int2 = 38 bytes por tupla; 7 x char (1) = 41 bytes; 7 x int4 = 52 bytes. –

1

Primero, ha preguntado acerca de 7, pero ahora 6 bytes. Seis valores de 8 bits se corresponden exactamente con el tamaño de la dirección MAC y el macaddr de tipo incorporado de PostgreSQL. Puede insertar esos bytes usando la sintaxis MAC f.i. A1-B2-C3-D4-E5-F6.

4

Hay pg_catalog.char (otra notación - "char") tipo que usa solo 1 byte para almacenar su valor.

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

select pg_column_size('A'::"char"); 
pg_column_size 
---------------- 
       1 
(1 row) 
+1

El tipo "char" solo puede "contar" de 0 a 127. Pruebe esto: 'select i, ascii (i ::" char ") de generate_series (0, 127) s (i)'. Ahora cambie 127 a 128. –

+4

@ClodoaldoNeto no es cierto, puede contar desde -128 a 127, intente con 'seleccionar i, ascii (i ::" char ") desde generate_series (-128, 127) s (i)' – TruongSinh

Cuestiones relacionadas