Pitch: Publiquei uma extensão de armazenamento para PostgreSQL 18 🐘
storage_engine: Armazenamento Colunar e por Lotes para PostgreSQL 18
storage_engine é uma extensão open-source que adiciona dois novos mecanismos de armazenamento (Table Access Methods) ao PostgreSQL — sem precisar modificar o core do banco:
→ colcompress — armazenamento colunar, leitura vetorizada, pruning de stripes por min/max (estilo MergeTree do ClickHouse, mas dentro do PostgreSQL)
→ rowcompress — linhas comprimidas em lotes, com suporte a DELETE/UPDATE e scan paralelo
Compressão real
Uma tabela de 3.353 MB de documentos fiscais (XML + metadados) ficou em 89 MB com colcompress/zstd — redução de 38× — sem perder nenhuma funcionalidade do PostgreSQL.
| Tabela | Engine | Tamanho | Redução |
|---|---|---|---|
| documentos_fiscais | heap | 3.353 MB | 1× |
| documentos_fiscais_col | colcompress/zstd | 104 MB | 32× |
| documentos_fiscais_col_sorted | colcompress/zstd + merge | 89 MB | 38× |
| documentos_fiscais_row | rowcompress/zstd | 110 MB | 30× |
Benchmark — 1 milhão de linhas, PostgreSQL 18
17 colunas (numérico, texto, JSONB, arrays, booleanos), compressão lz4, dados pré-ordenados por event_date e mergeados.
Serial (núcleo único, JIT off)
| Query | heap | colcompress | rowcompress | citus_columnar |
|---|---|---|---|---|
| count(*) full scan | 39 ms | 42 ms | 314 ms | 37 ms |
| SUM/AVG numérico+double | 181 ms | 119 ms | 364 ms | 126 ms |
| GROUP BY 10 países | 215 ms | 161 ms | 400 ms | 136 ms |
| GROUP BY + percentil p95 | 534 ms | 446 ms | 689 ms | 469 ms |
| DATE range (1 mês, pruned) | 21 ms | 23 ms | 60 ms | 21 ms |
| JSONB @> filtro | 125 ms | 159 ms | 329 ms | 237 ms |
| JSONB key + GROUP BY | 382 ms | 310 ms | 547 ms | 350 ms |
| Array @> filtro | 62 ms | 126 ms | 272 ms | 143 ms |
| LIKE text scan | 147 ms | 93 ms | 344 ms | 95 ms |
| Agregação pesada (10 métricas) | 1.953 ms | 1.970 ms | 2.098 ms | 1.948 ms |
Paralelo (JIT on, 16 workers)
| Query | heap | colcompress | rowcompress | citus_columnar |
|---|---|---|---|---|
| count(*) full scan | 18 ms | 16 ms | 149 ms | 38 ms |
| SUM/AVG numérico+double | 51 ms | 31 ms | 147 ms | 123 ms |
| DATE range (1 mês) | 21 ms | 29 ms | 70 ms | 21 ms |
| JSONB @> filtro | 83 ms | 44 ms | 471 ms | 240 ms |
| JSONB key + GROUP BY | 390 ms | 67 ms | 697 ms | 358 ms |
| Array @> filtro | 60 ms | 34 ms | 275 ms | 144 ms |
| LIKE text scan | 44 ms | 26 ms | 145 ms | 91 ms |
| Agregação pesada (10 métricas) | 1.960 ms | 674 ms | 2.111 ms | 1.957 ms |
O citus_columnar não paraleliza — os tempos são praticamente idênticos entre serial e paralelo. O colcompress alcança 2,9× de speedup na agregação pesada com 16 workers (1.970 ms → 674 ms).
Dois casos de uso, uma extensão
📊 Analítico (orderby + merge)
Defina um orderby, carregue os dados, execute engine.colcompress_merge(). O planner passa a ignorar stripes inteiras com base em estatísticas min/max — antes de descomprimir um único byte. Não crie índices B-tree nas colunas do orderby: um B-tree faz o planner escolher IndexScan, desabilitando o pruning.
SELECT engine.alter_colcompress_table_set('events'::regclass,
orderby => 'event_date ASC',
compression => 'lz4'
);
SELECT engine.colcompress_merge('events');
🗄️ Repositório de arquivos (index_scan)
Habilite index_scan = true por tabela. A extensão adiciona um scan path customizado que busca apenas as linhas apontadas pelo índice B-tree existente. Combina compressão zstd 30–38× com velocidade de point-lookup — ideal para tabelas de documentos (XML, PDF, JSON) onde cada busca é por chave específica.
SELECT engine.alter_colcompress_table_set('documents'::regclass,
compression => 'zstd',
index_scan => true
);
Instalação
git clone https://github.com/saulojb/storage_engine
cd storage_engine
sudo make -j$(nproc) install
-- postgresql.conf
shared_preload_libraries = 'storage_engine'
-- no banco
CREATE EXTENSION storage_engine;
CREATE TABLE events (...) USING colcompress;
🔗 GitHub: https://github.com/saulojb/storage_engine
📦 PGXN: https://pgxn.org/dist/storage_engine/
O kit de benchmark completo (SQL de setup, scripts de execução, gerador de gráficos) está em tests/bench/.
Proveniência: storage_engine é um fork reestruturado do Hydra Columnar, que por sua vez deriva do Citus Columnar (Citus Data / Microsoft). O formato colunar de base (stripes, chunks, compressão) vem desse trabalho upstream. As adições desta versão incluem: schema engine, rowcompress AM, orderby sort key por tabela, pruning de stripes por min/max, scan paralelo DSM, ANALYZE rápido por amostragem de chunk groups, DELETE/UPDATE para rowcompress, e os fixes de SIGSEGV e index scan. Atribuições completas no arquivo NOTICE (AGPLv3).
Saulo José Benvenutti — Arquiteto de Dados / DBA PostgreSQL
📧 saulojb@gmail.com · 🔗 github.com/saulojb