O Hologres armazena dados de tabelas em três formatos: orientado a linhas, orientado a colunas e híbrido. Cada formato é otimizado para diferentes padrões de consulta. Selecione o formato ao criar uma tabela, pois alterá-lo posteriormente exige recriar a tabela.
Escolher um formato de armazenamento
Use esta tabela para identificar o formato adequado à sua carga de trabalho. O padrão é orientado a colunas.
|
Orientado a colunas |
Orientado a linhas |
Híbrido |
|
|
Mais indicado para |
Cargas OLAP: consultas complexas, joins, varreduras completas e agregações |
Consultas pontuais por chave primária (PK) com alto QPS |
Tabelas que exigem tanto consultas pontuais por PK quanto análises OLAP; consultas pontuais sem PK |
|
Limite de colunas |
300 |
3.000 |
300 |
|
Índices padrão |
Múltiplos índices, incluindo índices bitmap para colunas de string |
Apenas índice de PK |
Índices de linha e coluna |
|
Overhead de armazenamento |
Baixo |
Baixo |
Mais alto (dados armazenados nos formatos de linha e coluna) |
|
Valor de |
|
|
|
O armazenamento híbrido gera maior overhead porque cada gravação se replica nas cópias orientadas a linhas e a colunas. Use-o apenas quando uma única tabela realmente precisar de buscas por PK e consultas analíticas simultaneamente.
Defina o formato de armazenamento
Especifique a propriedade orientation durante a criação da tabela.
A partir da V2.1:
CREATE TABLE <table_name> (...) WITH (orientation = '[column | row | row,column]');
Todas as versões:
BEGIN;
CREATE TABLE <table_name> (...);
CALL set_table_property('<table_name>', 'orientation', '[column | row | row,column]');
COMMIT;
Como funciona
Os três formatos diferem na disposição dos dados em disco e nos índices construídos. Essa diferença determina a eficiência para cada tipo de consulta.
No formato orientado a colunas, os valores de cada coluna ficam armazenados contiguamente. Uma consulta como SELECT SUM(revenue) FROM orders WHERE region = 'APAC' lê apenas as colunas revenue e region, ignorando as demais. Isso reduz a E/S em consultas analíticas que acessam um pequeno subconjunto de colunas em muitas linhas.
Já no formato orientado a linhas, os valores de cada linha ficam contíguos. Uma consulta como SELECT * FROM orders WHERE id = '1001' faz uma única busca por PK e recupera toda a linha em uma varredura. Esse método é eficiente quando você precisa de todas as colunas de uma linha específica imediatamente.
O formato híbrido mantém uma cópia orientada a linhas e outra orientada a colunas para cada registro. O otimizador de consultas escolha a cópia com melhor desempenho com base no plano de execução. Toda operação de escrita deve ser concluída com sucesso em ambas as cópias antes de retornar.
Orientado a colunas
Tabelas orientadas a colunas usam o formato ORC. Os dados são codificados com algoritmos como Run-Length Encoding (RLE) e codificação por dicionário, e depois compactados com Snappy, Zlib, Zstd ou LZ4. A camada de armazenamento também cria índices bitmap e usa materialização tardia para reduzir leituras desnecessárias.
Quando uma tabela orientada a colunas possui chave primária (PK), o sistema gera um identificador de linha (RID) para cada registro. Com índices como chave de distribuição ou chave de clustering definidos em colunas frequentemente consultadas, o mecanismo localiza rapidamente o shard e o arquivo correspondentes.
A partir da V2.1:
CREATE TABLE public.tbl_col (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT NOT NULL,
in_time TIMESTAMPTZ NOT NULL,
PRIMARY KEY (id)
)
WITH (
orientation = 'column',
clustering_key = 'class',
bitmap_columns = 'name',
event_time_column = 'in_time'
);
SELECT * FROM public.tbl_col WHERE id = '3333';
SELECT id, class, name FROM public.tbl_col WHERE id < '3333' ORDER BY id;
Todas as versões:
BEGIN;
CREATE TABLE public.tbl_col (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT NOT NULL,
in_time TIMESTAMPTZ NOT NULL,
PRIMARY KEY (id)
);
CALL set_table_property('public.tbl_col', 'orientation', 'column');
CALL set_table_property('public.tbl_col', 'clustering_key', 'class');
CALL set_table_property('public.tbl_col', 'bitmap_columns', 'name');
CALL set_table_property('public.tbl_col', 'event_time_column', 'in_time');
COMMIT;
SELECT * FROM public.tbl_col WHERE id = '3333';
SELECT id, class, name FROM public.tbl_col WHERE id < '3333' ORDER BY id;

Orientado a linhas
Tabelas orientadas a linhas usam o formato SST. Os dados ficam armazenados em blocos comprimidos e ordenados por chave. A camada de armazenamento constrói índices Block Index e Bloom Filter, enquanto um mecanismo de compactação em segundo plano organiza os arquivos para buscas eficientes por PK.
Recomendado: defina apenas a chave primária
Se a tabela orientada a linhas tiver PK, o sistema define automaticamente a PK como chave de distribuição e chave de clustering, além de gerar um RID para cada linha. Consultas pontuais baseadas em PK varrem apenas um índice de PK para recuperar todas as colunas.
Ao crie uma tabela orientada a linhas, defina somente a PK. O sistema configura automaticamente as chaves de distribuição e de clustering.
A partir da V2.1:
CREATE TABLE public.tbl_row (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT,
PRIMARY KEY (id)
)
WITH (
orientation = 'row',
clustering_key = 'id',
distribution_key = 'id'
);
-- PK-based point query
SELECT * FROM public.tbl_row WHERE id = '1111';
-- Multiple key lookup
SELECT * FROM public.tbl_row WHERE id IN ('1111', '2222', '3333');
Todas as versões:
BEGIN;
CREATE TABLE public.tbl_row (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT,
PRIMARY KEY (id)
);
CALL set_table_property('public.tbl_row', 'orientation', 'row');
CALL set_table_property('public.tbl_row', 'clustering_key', 'id');
CALL set_table_property('public.tbl_row', 'distribution_key', 'id');
COMMIT;
-- PK-based point query
SELECT * FROM public.tbl_row WHERE id = '1111';
-- Multiple key lookup
SELECT * FROM public.tbl_row WHERE id IN ('1111', '2222', '3333');

Não recomendado: divergência entre PK e chave de clustering
Se você definir campos diferentes para a PK e a chave de clustering, cada consulta baseada em PK exigirá duas varreduras:
Use o índice de PK para localizar o valor da chave de clustering e o RID.
Use a chave de clustering e o RID para buscar a linha completa.
Esse padrão de varredura dupla reduz significativamente o desempenho das consultas.
A partir da V2.1:
-- Avoid: clustering_key differs from PK
CREATE TABLE public.tbl_row (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT,
PRIMARY KEY (id)
)
WITH (
orientation = 'row',
clustering_key = 'name', -- different from PK (id)
distribution_key = 'id'
);
Todas as versões:
BEGIN;
CREATE TABLE public.tbl_row (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT,
PRIMARY KEY (id)
);
CALL set_table_property('public.tbl_row', 'orientation', 'row');
CALL set_table_property('public.tbl_row', 'clustering_key', 'name'); -- different from PK (id)
CALL set_table_property('public.tbl_row', 'distribution_key', 'id');
COMMIT;

Híbrido
Introduzido na V1.1, o armazenamento híbrido mantém os dados simultaneamente nos formatos orientado a linhas e orientado a colunas. Uma chave primária é obrigatória. Cada escrita é concluída atomicamente: a operação só tem êxito após a gravação em ambas as cópias.
Durante as consultas, o otimizador selecione o formato mais eficiente:
Consultas pontuais por PK (
SELECT * FROM tbl WHERE pk = xxx) e cenários de Fixed Plan: caminho orientado a linhas.Consultas pontuais sem PK (
SELECT * FROM tbl WHERE col1 = xx AND col2 = yyy): o otimizador lê primeiro as linhas correspondentes na cópia orientada a colunas e depois busca as linhas completas na cópia orientada a linhas usando os valores de chave recuperados. Isso evita varreduras completas na tabela e retorna todas as colunas.Consultas gerais: caminho orientado a colunas.
A partir da V2.1:
CREATE TABLE public.tbl_row_col (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT NOT NULL,
PRIMARY KEY (id)
)
WITH (
orientation = 'row,column',
distribution_key = 'id',
clustering_key = 'class',
bitmap_columns = 'name'
);
SELECT * FROM public.tbl_row_col WHERE id = '2222'; -- PK point query
SELECT * FROM public.tbl_row_col WHERE class = 'Class Two'; -- Non-PK point query
SELECT * FROM public.tbl_row_col WHERE id = '2222' AND class = 'Class Two'; -- General OLAP query
Todas as versões:
BEGIN;
CREATE TABLE public.tbl_row_col (
id TEXT NOT NULL,
name TEXT NOT NULL,
class TEXT,
PRIMARY KEY (id)
);
CALL set_table_property('public.tbl_row_col', 'orientation', 'row,column');
CALL set_table_property('public.tbl_row_col', 'distribution_key', 'id');
CALL set_table_property('public.tbl_row_col', 'clustering_key', 'class');
CALL set_table_property('public.tbl_row_col', 'bitmap_columns', 'name');
COMMIT;
SELECT * FROM public.tbl_row_col WHERE id = '2222'; -- PK point query
SELECT * FROM public.tbl_row_col WHERE class = 'Class Two'; -- Non-PK point query
SELECT * FROM public.tbl_row_col WHERE id = '2222' AND class = 'Class Two'; -- General OLAP query

Exemplos de uso
Os exemplos abaixo usam a sintaxe WITH (orientation = ...) da V2.1. Para a sintaxe equivalente com set_table_property, compatível com todas as versões, consulte as seções anteriores.
-- Column-oriented table (default)
CREATE TABLE tbl_col (
a INT NOT NULL,
b TEXT NOT NULL
)
WITH (
orientation = 'column'
);
-- Row-oriented table
CREATE TABLE public.tbl_row (
a INTEGER NOT NULL,
b TEXT NOT NULL,
PRIMARY KEY (a)
)
WITH (
orientation = 'row'
);
-- Hybrid table (row + column)
CREATE TABLE tbl_col_row (
pk TEXT NOT NULL,
col1 TEXT,
col2 TEXT,
col3 TEXT,
PRIMARY KEY (pk)
)
WITH (
orientation = 'row,column'
);
Perguntas frequentes
Se o armazenamento híbrido suporta consultas pontuais por PK e consultas OLAP, por que não usá-lo sempre?
O armazenamento híbrido gera maior overhead porque os dados são gravados duas vezes: uma no formato de linha e outra no formato de coluna. Use-o apenas quando uma única tabela realmente precisar de buscas por PK com alto QPS e consultas analíticas. Para tabelas exclusivamente OLAP, o armazenamento orientado a colunas é mais eficiente. Para tabelas focadas apenas em buscas por PK, o armazenamento orientado a linhas evita esse custo adicional.
É possível alterar o formato de armazenamento de uma tabela após a criação?
Não. A conversão direta não é suportada. Para mudar o formato, crie a tabela com o novo valor de orientation.
Por que o armazenamento orientado a linhas suporta mais colunas que o orientado a colunas?
Tabelas orientadas a colunas criam múltiplos índices por padrão, incluindo índices bitmap para colunas de string. À medida que o número de colunas aumenta, esses índices elevam o overhead de armazenamento e tornam as escritas mais lentas. Tabelas orientadas a linhas indexam apenas a chave primária, portanto o custo por coluna é muito menor.
O que acontece se uma tabela orientada a linhas ultrapassar 3.000 colunas ou uma tabela orientada a colunas ultrapassar 300 colunas?
Esses são limites recomendados, não rígidos. Excedê-los degrada o desempenho: tabelas orientadas a colunas com muitas colunas sofrem com alto custo de indexação e escrita; tabelas orientadas a linhas com excesso de colunas aumentam o tamanho da linha e reduzem o throughput de consultas pontuais. Mantenha-se dentro dos limites recomendados para cargas de produção.
Próximos passos
Para obter orientações sobre como combinar a escolha do formato de armazenamento com outras propriedades da tabela — como chave de distribuição, chave de clustering e particionamento — com base nos seus padrões de consulta, consulte o Guia de otimização de criação de tabelas baseado em cenários.