antonio leandro

estruturas e algoritmos

Designing Access Methods: The RUM Conjecture

paper · núcleo · Manos Athanassoulis, Michael S. Kester, Lukas M. Maas, et al. · · ~25 min de leitura do original · leve

a tese

todo método de acesso paga em três moedas — leitura, escrita e espaço — e fixar um teto em duas delas cria um piso na terceira: não existe estrutura universalmente ótima, só escolha de dívida

o que fica

  1. Os três overheads são amplificações, não custos absolutos: read, write e space amplification, cada uma medida como razão sobre os dados-base, com mínimo teórico de 1,0.
  2. Otimizar leitura ao extremo estoura o espaço: guardar cada valor no bloco cujo ID é o próprio valor dá RO igual a 1,0, mas o MO tende ao infinito e o UO vira 2,0, porque trocar um valor mexe em dois blocos.
  3. O log puro é o ótimo de escrita, com UO igual a 1,0, e o preço é que leitura e espaço crescem sem limite enquanto os updates se acumulam sem consolidação.
  4. A conjectura nunca foi provada: o próprio paper lista "provar a conjectura RUM" como trabalho futuro e se apresenta como visionary paper, não como teorema.
  5. O trade-off vale por nível da hierarquia de memória: dá para reduzir leitura e escrita no nível n guardando mais dados no nível n−1, o que apenas empurra o overhead de espaço para cima.
  6. Cache-oblivious sai caro em constante de leitura e em ponteiros, e é justamente por isso que estrutura sintonizável precisa ser cache-aware: sem conhecer a hierarquia não há botão para girar.

o problema

A forma como os dados ficam no disco, no flash, na memória ou no cache decide o que dá para fazer com eles. Heap file sem índice obriga a varrer tudo para achar uma tupla. Uma árvore em cima do heap troca a varredura por uma sondagem barata, e cobra espaço extra por isso. Quatro décadas de pesquisa produziram uma pilha de propostas — cada uma afinada para um padrão de workload ou para uma característica de hardware que estava em alta naquele ano.

O incômodo é que o problema nunca fecha. Nos anos 1970 a obsessão era minimizar acesso aleatório a disco; quarenta anos depois a estratégia é a mesma, só que o alvo virou acesso aleatório à memória principal. Hardware e aplicação mudam rápido e continuamente, e a cada mudança alguém redesenha a estrutura de dados. Faltava um vocabulário comum para comparar essas propostas e para dizer, antes de gastar um ano, o que uma escolha de design está condenando a piorar.

a ideia

Os autores observam que todo projeto de método de acesso está tentando minimizar as mesmas três quantidades: overhead de leitura (R), de update (U) e de memória ou armazenamento (M). Daí vem a conjectura RUM: um método de acesso que estabelece um teto para dois dos três overheads também estabelece um piso duro para o terceiro. Você escolhe dois para otimizar e paga no que sobrou.

Não é um teorema. É uma conjectura declarada como tal, num paper explicitamente rotulado como visionary. O valor está menos na prova, que não existe, e mais no sistema de coordenadas: passa a ser possível colocar qualquer estrutura num mapa e perguntar que dívida ela escolheu.

como funciona

Os três overheads são definidos como razões sobre os dados-base, não como custos absolutos. O read overhead é a amplificação de leitura: total lido, incluindo dados auxiliares, dividido pelo que se queria ler. O update overhead é a amplificação de escrita: tamanho das escritas físicas de um update lógico dividido pelo tamanho do update lógico. O memory overhead é a amplificação de espaço: espaço de auxiliar mais base dividido pelo espaço da base. O mínimo teórico de cada um é 1,0.

O argumento roda sobre um caso propositalmente bobo: um array de N inteiros de tamanho fixo, um valor por bloco, workload de point queries, inserts, updates e deletes. Três designs degenerados fecham as três pontas.

Para minimizar só leitura, guarde cada valor no bloco cujo ID é o próprio valor. O conjunto {1, 17} ocupa dezessete blocos. RO fica em 1,0, porque você sempre sabe onde olhar e só lê dado útil, mas MO é ilimitado — não dá para prever o maior valor que um dia será inserido — e trocar um valor exige esvaziar um bloco e preencher outro, levando UO a 2,0.

Para minimizar só escrita, anexe todo update num log que só cresce. UO chega a 1,0. Qualquer reorganização que baixasse RO subiria UO de novo, então leitura e espaço crescem indefinidamente.

Para minimizar só espaço, não guarde nada auxiliar: array denso, updates in place. MO dá 1,0 e UO também, e o RO no pior caso vira N, porque só resta varrer.

Com isso o paper monta um triângulo e distribui as famílias conhecidas nele: hash, B-Tree, trie, skiplist no canto de leitura; LSM, Partitioned B-tree, MaSM, Positional Differential Tree no canto de escrita; Bloom filter, bitmaps, ZoneMaps, Column Imprints no canto de espaço; cracking e adaptive merging no meio. Uma tabela de complexidades reforça que não há vencedor único: hash index dá point query em O(1), B+-Tree dá o melhor range query, ZoneMaps dá o menor índice, LSM segura range query razoável com custo de update baixo. E o mesmo trade-off se repete verticalmente: baixar RO e UO no nível n da hierarquia de memória custa MO no nível n−1.

o que isso custou

A conjectura não é provada, e o paper não propõe técnica de prova — coloca isso na lista de trabalho futuro, junto com “modelar os overheads” e “documentar as manifestações”. O modelo é deliberadamente simplista: array de inteiros, blocos de tamanho fixo, operações pontuais. Concorrência, latência versus vazão e custo de CPU ficam de fora.

Os próprios autores admitem a brecha mais séria: em implementações reais dá para otimizar os três “até certo ponto”, usando computação e conhecimento sobre os dados no lugar de metadados. Clustered index em bloco reduz leitura e espaço ao mesmo tempo, com custo de aritmética extra para achar a tupla. Bitmap comprimido idem. Compressão é tratada como ortogonal à conjectura, o que é uma escolha de escopo, não uma demonstração.

E o alvo declarado — um método de acesso único que transite entre os três extremos — o paper reconhece que talvez não seja viável, sugerindo no lugar um conjunto de estruturas que cubram o espaço em agregado. Estruturas adaptativas como cracking se movem no espaço RUM, mas não são sintonizáveis: elas vão para onde as queries mandam, não para onde você mandaria.

onde isso aparece hoje

O que sobreviveu foi o vocabulário. Falar de read, write e space amplification como um trio que se compensa é hoje a maneira corrente de discutir tuning de engine LSM — e Mark Callaghan, do Facebook, assina o paper ao lado do grupo de Harvard e da EPFL. A lista de direções propostas descreve bem o que veio a ser perseguido depois: B+-Trees com altura, tamanho de nó e condição de split ajustados em runtime; índices aproximados que absorvem updates em estruturas probabilísticas atualizáveis; bitmaps que engolem update em bitvectors compressíveis; logs iterativos com filtros por cima para evitar leitura desnecessária.

Para quem escolhe estrutura de dados em produção, a utilidade imediata é diagnóstica. Antes de trocar de índice, vale nomear qual das três amplificações está doendo e aceitar, explicitamente, em qual das outras duas a conta vai cair.

lido na íntegra por pipeline de llm, revisado por antonio leandro antes de publicar ·