PostgreSQL bytea vs smallint []

9

Estoy buscando importar datos grandes (100Mb - 1 GB) de series de tiempo multicanal en una base de datos PostgreSQL. Los datos provienen de archivos en formato EDF que los agrupan en "registros" o "épocas" de unos pocos segundos cada uno. El registro de cada época contiene las señales para cada canal de datos como matrices secuenciales de enteros cortos.

Tengo el mandato de almacenar los archivos dentro de la base de datos, en el peor de los casos como BLOB. Dado eso, me gustaría investigar opciones que me permitan hacer algo más con los datos dentro de la base de datos, como facilitar consultas basadas en los datos de la señal.

Mi plan inicial es almacenar los datos como una fila por registro de época. Lo que intento sopesar es si almacenar los datos de la señal real como bytea o smallint [] (o incluso smallint [] []). ¿Alguien podría recomendar uno sobre el otro? Estoy interesado en los costos de almacenamiento y acceso. Es probable que el uso se inserte una vez, se lea ocasionalmente y nunca se actualice. Si uno se envolviera más fácilmente como un tipo personalizado de modo que pudiera agregar funciones para analizar y comparar registros, mucho mejor.

Sin duda no tengo muchos detalles, así que siéntase libre de agregar comentarios sobre lo que desea que aclare.

beldaz
fuente
2
Este podría ser uno de los pocos usos razonables para el uso de matrices en el modelo de datos de autoría, ya que ahorra mucho espacio en disco al evitar la sobrecarga de la fila de 24 a 28 bytes. Las matrices también se comprimen y almacenan fuera de línea si son lo suficientemente largas.
Craig Ringer
beldaz, la forma en que debe almacenar los datos tiene mucho que ver con cómo planea acceder a ellos y con qué frecuencia. Si rara vez se consultan los datos, y siempre desea extraer los datos por registro, entonces creo que una fila por registro en una matriz tiene sentido. Sin embargo, si desea realizar cualquier consulta que sea un poco más profunda, como extraer todos los registros de un paciente_id dado, por ejemplo, entonces quizás podamos sugerir una ligera mejora en la estructura de almacenamiento. ¿Alguna idea sobre sus patrones de consulta?
Chris
@ Chris Gracias. He omitido el componente de metadatos, ya que es muy pequeño y puede residir en una relación separada. Los patrones de consulta son TBD, pero es posible que desee comparar dos archivos diferentes grabados al mismo tiempo y extraer señales de épocas simultáneas.
beldaz
@CraigRinger No vi mucha evidencia de compresión de matriz. ¿Esto necesita ser habilitado de alguna manera?
beldaz

Respuestas:

11

En ausencia de respuestas, he explorado el tema más yo mismo.

Parece que las funciones definidas por el usuario pueden manejar todos los tipos base, incluidos bytea y smallint[], por lo que esto no afecta mucho la elección de la representación.

Probé varias representaciones diferentes en un servidor PostgreSQL 9.4 que se ejecuta localmente en una computadora portátil Windows 7 con una configuración estándar. Las relaciones para almacenar esos datos de señal reales fueron las siguientes.

Objeto grande para todo el archivo

CREATE TABLE BlobFile (
    eeg_id INTEGER PRIMARY KEY,
    eeg_oid OID NOT NULL
);

Matriz SMALLINT por canal

CREATE TABLE EpochChannelArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal SMALLINT[] NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

BYTEA por canal en cada época

CREATE TABLE EpochChannelBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

SMALLINT 2D array por época

CREATE TABLE EpochArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals SMALLINT[][] NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

Conjunto de BYTEA por época

CREATE TABLE EpochBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

Luego importé una selección de archivos EDF en cada una de estas relaciones a través de Java JDBC y comparé el crecimiento del tamaño de la base de datos después de cada carga.

Los archivos fueron:

  • Archivo A: 2706 épocas de 16 canales, cada canal 1024 muestras (16385 muestras por época), 85 MB
  • Archivo B: 11897 épocas de 18 canales, cada canal 1024 muestras (18432 muestras por época), 418 MB
  • Archivo C: 11746 épocas de 20 canales, cada canal de 64 a 1024 muestras (17088 muestras por época), 382 MB

En términos de costo de almacenamiento, aquí está el tamaño ocupado en MB para cada caso: Costo de almacenamiento en MB

En relación con el tamaño del archivo original, los objetos grandes eran aproximadamente un 30-35% más grandes. Por el contrario, almacenar cada época como BYTEA o SMALLINT [] [] era menos del 10% más grande. El almacenamiento de cada canal como una tupla separada proporciona un aumento del 40%, ya sea BYTEA o SMALLINT [], por lo que no es mucho peor que almacenarlo como un objeto grande.

Una cosa que no había apreciado inicialmente es que "las matrices multidimensionales deben tener extensiones coincidentes para cada dimensión" en PostgreSQL . Esto significa que la SMALLINT[][]representación solo funciona cuando todos los canales de una época tienen el mismo número de muestras. Por lo tanto, el archivo C no funciona con la EpochArrayrelación.

En términos de costos de acceso, no he jugado con esto, pero al menos en términos de insertar los datos inicialmente, la representación más rápida fue EpochByteay BlobFile, con EpochChannelArrayla más lenta, tardó aproximadamente 3 veces más que las dos primeras.

beldaz
fuente
Desde una perspectiva académica, considero que sus resultados son muy interesantes, pero desde un punto de vista práctico, ¿el tamaño del almacenamiento es motivo de gran preocupación? ¿Quizás en su caso de uso tiene muchos registros, por lo que el almacenamiento es un problema que enfrenta? Sin embargo, en este formato de almacenamiento, cualquier búsqueda que no sea por época (o canal, cuando se encuentra en el esquema apropiado) requeriría leer una parte de cada registro. ¿Está bien para su aplicación?
Chris
Prácticamente sí, ciertamente es importante para mí, ya que espero lidiar con varios TB de archivos sin formato. Resulta que la corriente en los gastos generales es menor de lo que esperaba, pero si hubiera sido del 300% para una representación en particular, sin duda la evitaría. En cuanto a las consultas, no esperaría acceder por otra cosa que no sea epoch y channel.
beldaz