PostgreSQL bytea vs smallint []

9

Estou procurando importar grandes dados de séries temporais multicanal (100Mb - 1 GB) para um banco de dados PostgreSQL. Os dados são provenientes de arquivos no formato EDF que agrupam os dados em "registros" ou "épocas", geralmente com alguns segundos cada. O registro de cada época mantém os sinais para cada canal de dados como matrizes sequenciais de números inteiros curtos.

Sou mandatado para armazenar os arquivos no banco de dados, na pior das hipóteses como BLOBs. Dado isso, gostaria de investigar opções que me permitiriam fazer algo mais com os dados no banco de dados, como facilitar consultas com base nos dados do sinal.

Meu plano inicial é armazenar os dados como uma linha por registro de época. O que estou tentando avaliar é se os dados reais do sinal são armazenados como tipos de bytea ou smallint [] (ou mesmo smallint [] []). Alguém poderia recomendar um sobre o outro? Estou interessado nos custos de armazenamento e acesso. É provável que o uso seja inserido uma vez, leia ocasionalmente, atualize nunca. Se alguém fosse mais facilmente agrupado como um tipo personalizado, de modo que eu pudesse adicionar funções para analisar a comparação de registros, tanto melhor.

Sem dúvida, tenho poucos detalhes, portanto, fique à vontade para adicionar comentários sobre o que você gostaria que eu esclarecesse.

Beldaz
fonte
2
Esse pode ser um dos poucos usos sensatos para uso de matriz no modelo de dados autoritário, pois você economiza muito espaço em disco, evitando a sobrecarga de linha de 24 a 28 bytes. As matrizes também são compactadas e armazenadas fora de linha, se o tempo suficiente.
Craig Ringer
beldaz, a maneira pela qual você deve armazenar os dados tem muito a ver com a maneira como planeja acessá-los e com que frequência. Se os dados raramente são consultados e você sempre deseja extrair os dados por registro, acho que uma linha por registro em uma matriz faz sentido. No entanto, se você desejar fazer uma consulta um pouco mais profunda, como extrair todos os registros de um determinado ID de paciente, por exemplo, talvez possamos sugerir uma pequena melhoria na estrutura de armazenamento. Alguma idéia sobre seus padrões de consulta?
22415 Chris
@ Chris Obrigado. Eu deixei de fora o componente de metadados, pois ele é muito pequeno e pode residir em uma relação separada. Os padrões de consulta são TBD, mas posso comparar dois arquivos diferentes gravados ao mesmo tempo e extrair sinais de épocas simultâneas.
beldaz
@ CraigRinger Eu não vi muita evidência de compressão de array. Isso precisa ser ativado de alguma forma?
beldaz

Respostas:

11

Na ausência de respostas, eu também explorei a questão.

Parece que as funções definidas pelo usuário podem lidar com todos os tipos de base, incluindo bytea e smallint[], portanto, isso não afeta muito a escolha da representação.

Tentei várias representações diferentes em um servidor PostgreSQL 9.4 em execução localmente em um laptop Windows 7 com uma configuração de baunilha. As relações para armazenar os dados reais do sinal foram as seguintes.

Objeto grande para o arquivo inteiro

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 em 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)
);

Matriz 2D SMALLINT por época

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

Matriz BYTEA por época

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

Em seguida, importei uma seleção de arquivos EDF para cada uma dessas relações via Java JDBC e comparei o crescimento no tamanho do banco de dados após cada upload.

Os arquivos foram:

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

Em termos de custo de armazenamento, eis o tamanho ocupado em MB para cada caso: Custo de armazenamento em MB

Em relação ao tamanho do arquivo original, os Objetos Grandes eram cerca de 30 a 35% maiores. Por outro lado, o armazenamento de cada época como BYTEA ou SMALLINT [] [] era menos de 10% maior. Armazenar cada canal como uma tupla separada gera um aumento de 40%, como BYTEA ou SMALLINT [], portanto não é muito pior do que armazenar como um objeto grande.

Uma coisa que eu não havia apreciado inicialmente é que "matrizes multidimensionais devem ter extensões correspondentes para cada dimensão" no PostgreSQL . Isso significa que a SMALLINT[][]representação só funciona quando todos os canais de uma época têm o mesmo número de amostras. Portanto, o arquivo C falha ao trabalhar com a EpochArrayrelação.

Em termos de custos de acesso, não brinquei com isso, mas pelo menos em termos de inserir os dados inicialmente, a representação mais rápida foi EpochByteae BlobFile, com EpochChannelArraya mais lenta, demorou cerca de três vezes o tempo das duas primeiras.

Beldaz
fonte
Do ponto de vista acadêmico, acho seus resultados muito interessantes, mas do ponto de vista prático, o tamanho do armazenamento é de grande preocupação? Talvez no seu caso de uso você tenha muitos registros e, portanto, o armazenamento seja um problema que você enfrenta? No entanto, nesse formato de armazenamento, qualquer pesquisa que não seja por época (ou canal, quando no esquema apropriado) exigiria a leitura de uma parte de cada registro. Isso é bom para o seu aplicativo?
22415 Chris
Praticamente sim, certamente é importante para mim, pois espero lidar com vários TB de arquivos brutos. Acontece que a corrente de sobrecarga é menor do que eu esperava, mas se tivesse sido de 300% para uma representação específica, certamente a evitaria. Quanto à consulta, eu não esperaria acessar por outra coisa senão época e canal.
beldaz