Como um exemplo simplificado, suponha que eu tenha uma tabela como esta:
seq | value
----+------
102 | 11954
211 | 43292
278 | 19222
499 | 3843
A tabela pode conter centenas de milhões de registros, e eu preciso fazer consultas frequentemente como esta:
SELECT sum(value) WHERE seq > $a and seq < $b
Mesmo se seq
estiver indexado, uma implementação típica de banco de dados percorrerá cada linha para calcular a soma no melhor dos casos O(n)
, onde n
é o tamanho do intervalo.
Existe algum banco de dados que possa fazer isso com eficiência, como em O(log(n))
consulta?
Encontrei uma estrutura de dados chamada Árvore de Segmentos, conforme descrito aqui . Às vezes também chamado de árvore de intervalo ou árvore de intervalo, embora todos esses nomes sejam descritos como uma variação ligeiramente diferente da estrutura de dados.
No entanto, não encontrei nenhum banco de dados que implemente essa estrutura de dados. Implementá-lo do zero é fácil para uma estrutura na memória, mas torna-se complicado se for necessário persistir ou for grande demais para caber na memória. Se houver um padrão eficiente para implementar isso em um banco de dados existente, isso também poderá ajudar.
Nota lateral: Esta não é uma tabela apenas anexada; portanto, uma solução como manter uma soma acumulada não funcionará neste caso.
Respostas:
Usando índices do SQL Server ColumnStore
Bem, ok, apenas um - um índice CS agrupado.
Se você quiser ler sobre o hardware em que fiz isso, vá até aqui . Divulgação completa, escrevi essa postagem no site da empresa em que trabalho.
Para o teste!
Aqui está um código genérico para criar uma tabela muito grande. Mesmo aviso que Evan, isso pode demorar um pouco para criar e indexar.
Bem, Evan vence pela simplicidade, mas eu já falei sobre isso antes.
Aqui está a definição do índice. La e dee e dah.
Observando uma contagem, todo ID tem uma distribuição bastante uniforme:
Resultados:
...
Com cada ID tendo ~ 5.005.005 linhas, podemos observar um intervalo muito pequeno de IDs para obter uma soma de 10 milhões de linhas.
Resultado:
Perfil da consulta:
Por diversão, uma agregação maior:
Resultados:
Perfil da consulta:
Espero que isto ajude!
fonte
PostgreSQL com um índice BRIN
Isso não é verdade. Pelo menos, nenhum banco de dados decente fará isso. O PostgreSQL suporta a criação de índices BRIN nesses tipos de tabelas. Os índices BRIN são super pequenos e podem caber em memória RAM, mesmo em tabelas tão grandes. Centenas de milhões de linhas não são nada.
Aqui, 300 milhões de linhas definidas como você solicitou. Aviso: pode levar muito tempo para criá-lo (Tempo: 336057.807 ms + 95121.809 ms para o índice).
E agora...
1,4 segundos para agregar / somar 5.889.135 linhas no intervalo especificado.
Apesar de a tabela ter 10 GB, o índice BRIN é de 304 kB.
Ainda mais rápido
Se isso ainda não for rápido o suficiente, você poderá armazenar em cache os agregados em 100 mil linhas.
Agora você só precisará usar as
2(1e5-1)
linhas brin e agregada em vez de 300 milhões ou o que quer.Hardware
Lenovo x230, i5-3230M, 16GB RAM, 1 TB Samsung 840 SSD.
fonte
O(n)
, talvezO(sqrt(n))
. Depende de como você definirá os intervalos a serem utilizados na materialização.