Estou tentando estender o PostgreSQL para indexar cadeias de bits de até 1000 bits. (Essas cadeias de bits são criadas pela quantização de vetores de alta dimensão, portanto, para cada dimensão, até 4 bits são atribuídos). As inserções são pouco frequentes, enquanto as pesquisas são a operação mais usada. Em uma pesquisa, gostaria de obter todas as linhas que correspondem exatamente à string de bits.
Parece um trabalho perfeito para GIN (em combinação com meu próprio tipo de dados), ou o que você acha?
Use um índice B-Tree, o tipo padrão. Não vejo caso para um índice GIN aqui.
Até 1.000 bits resultam em até 133 bytes (ou um pouco mais) de tamanho de armazenamento em disco para um
bit varying
tipo .Nem tanto . Um índice B-Tree simples deve servir. Mas talvez a coluna seja grande o suficiente para que os seguintes truques melhorem o desempenho.
Se uma pequena parte da coluna de cadeia de bits for distinta o suficiente para restringir sua pesquisa a poucos resultados, um índice em uma expressão pode fornecer melhor desempenho, porque o índice menor pode caber na RAM e é mais rápido de processar. Não se preocupe com mesas pequenas, a sobrecarga consumiria o benefício. Mas pode fazer uma grande diferença para mesas grandes .
Exemplo
tabela dada:
Se os primeiros 10 bits forem suficientes para restringir uma pesquisa a alguns resultados, você poderá criar um índice na expressão
b_col::bit(10)
. A conversão parabin(n)
trunca obitstring
bit para n.Parênteses extras são necessários para o operador de conversão em uma definição de índice. Ver:
Então, em vez da consulta
Você usaria:
Esteja ciente de que valores mais curtos são preenchidos com
0
's à direita (bits menos significativos) quando convertidos embit(n)
.Em um aplicativo do mundo real, isso começa a fazer sentido com várias centenas de bits. Teste o ponto de virada.
Otimize ainda mais
Como a maioria das instalações opera com
MAXALIGN
8 bytes (sistema operacional de 64 bits) ( mais detalhes aqui ), o tamanho do índice é o mesmo para todos os dados que não excedam 8 bytes. Efetivamente, por linha:Mais algumas despesas gerais menores por página e índice/tabela. Detalhes no manual ou nesta resposta relacionada em stackoverflow .
Portanto, você deve ser capaz de otimizar ainda mais a abordagem acima. Pegue o primeiro 64 bits (ou o último ou o que for mais distinto e funcione para você), converta-o
bigint
e crie um índice nessa expressão.Eu lancei duas vezes (
b_col::bit(64)::bigint
) pois não há elenco definido entrevarbit
ebigint
. Detalhes nesta resposta relacionada no SO:Efetivamente, esta é apenas uma função de hash muito rápida e simples, onde o valor de hash também permite procurar intervalos de valores. Dependendo dos requisitos exatos, você pode ir um passo além e usar qualquer
IMMUTABLE
função de hash semelhantemd5()
. Detalhes na resposta vinculada acima.A consulta para ir junto com isso:
O índice resultante deve ser tão grande quanto o do primeiro exemplo, mas as consultas devem ser consideravelmente mais rápidas por três motivos:
O índice normalmente retorna muito menos acessos (64 bits de informação versus 10 bits)
O Postgres pode trabalhar com aritmética inteira, que deve ser mais rápida, mesmo para uma
=
operação simples. (Não testei para verificar isso.)O tipo
integer
não tem sobrecarga comovarbit
- 5 ou 8 bytes . (Na minha instalação 5 bytes para até 960 bits , 8 bytes para mais).Efetivamente, para manter o índice em seu tamanho mínimo, você só pode compactar 24 bits em um
varbit
índice - em comparação com 64 bits de informação para umbigint
índice.CLUSTER
Nesse caso,
CLUSTER
deve melhorar o desempenho:É uma operação única e deve ser repetida em intervalos de seu projeto. Certifique-se de ler o manual sobre
CLUSTER
se você quiser usar isso. Ou considere as ferramentas da comunidade como pg_repack ou pg_suqeeze . Detalhes:Se os primeiros 64 bits de seus valores forem exclusivos na maioria das vezes,
CLUSTER
isso dificilmente ajudará, pois a varredura de índice retornará uma única linha na maioria dos casos. Se não,CLUSTER
vai ajudar muito . Consequentemente, o efeito será muito maior para o primeiro exemplo com o índice menos otimizado.