antonio leandro

dados e armazenamento

Predicate Caching: Query-Driven Secondary Indexing for Cloud Data Warehouses

paper · Tobias Schmidt, Andreas Kipf, Dominik Horn, Gaurav Saxena, Tim Kraska · · ~21 min de leitura do original

a tese

cache não precisa guardar o resultado: guardar as faixas de tuplas que passaram no predicado dá um índice secundário que nasce da própria carga de trabalho e não precisa ser recomputado a cada escrita

o que fica

  1. Cargas de data warehouse na nuvem são altamente repetitivas: usuários e sistemas mandam a mesma query muitas vezes, e é essa repetição que paga qualquer cache.
  2. Result cache e materialized view envelhecem mal: um insert, delete ou update entre duas repetições já deixa o cache obsoleto.
  3. Guardar posição custa menos que guardar resposta — o predicate cache indexa faixas de tuplas que passaram no predicado, não o resultado da query.
  4. Um índice construído a partir das queries já executadas dispensa alguém escolher as colunas de antemão: a carga de trabalho escolhe.
  5. O ganho declarado é de até 10x em queries selecionadas com overhead de construção desprezível, e o "até" e o "selecionadas" são o tamanho real da afirmação.
  6. A ideia foi validada como protótipo dentro do Amazon Redshift, não como recurso anunciado do produto.

o problema

Data warehouse na nuvem não recebe uma sequência de perguntas novas. Recebe a mesma pergunta de novo. Dashboard que atualiza de hora em hora, pipeline de ETL que roda todo dia, ferramenta de BI que remonta o mesmo filtro toda vez que alguém abre a aba: os autores observam que as cargas dos clientes têm padrões de query altamente repetitivos. Essa repetição é um convite óbvio a cachear alguma coisa, e a resposta padrão da indústria é cachear o mais caro possível — o resultado inteiro, via result cache ou materialized view.

O convite tem uma armadilha. Entre duas execuções da mesma query, a tabela muda. Chega carga nova, alguém corrige uma linha, um processo apaga um período. O resultado guardado vira mentira, e o sistema precisa ou invalidar o cache (perdendo o benefício justamente nas tabelas mais ativas, que são as interessantes) ou recomputar a view (pagando de novo o custo que o cache existia para evitar). O outro caminho clássico, criar índice secundário de verdade sobre as colunas filtradas, esbarra em dois pedágios: alguém precisa adivinhar quais colunas indexar antes de ver as queries, e o índice precisa ser mantido a cada escrita.

a ideia

O movimento do paper é mudar o que se guarda. Em vez de guardar a resposta, guarde onde a resposta estava.

Quando um scan de tabela base roda com um predicado, o motor já fez o trabalho de descobrir quais tuplas passam no filtro. Esse trabalho é jogado fora ao fim da query. O predicate caching o retém em forma comprimida: faixas de tuplas qualificadas para aquele predicado. Da próxima vez que o mesmo predicado aparecer — no mesmo dashboard, no mesmo join — o motor não precisa varrer o que já sabe que não qualifica.

A consequência é que o índice deixa de ser uma decisão de schema e vira um subproduto da execução. Ele se constrói sozinho, a partir das queries que de fato rodaram, e cobre exatamente os predicados que a carga usa. Os autores descrevem o resultado como leve, construído on the fly e mantido online sem recomputação — a diferença de natureza em relação ao result cache: uma faixa de posições resiste a mudanças que destroem uma resposta materializada.

o que isso custou

O material disponível é o resumo do trabalho, e ele não abre o mecanismo de invalidação. A afirmação de que o índice fica online sem recomputação é a parte mais interessante e é justamente a que exigiria ver o texto completo para avaliar: qualquer estrutura que aponte para posições de tuplas precisa de uma história sobre o que acontece quando linhas são deletadas ou reescritas. O paper afirma que essa história existe; o resumo não a conta.

Os limites que o próprio resumo declara são igualmente importantes. O ganho é de “até 10x” em “queries selecionadas”. Isso não é a melhora média da carga: é o teto, medido onde a técnica funciona bem. O overhead de construção é descrito como desprezível, o que é coerente com a ideia de aproveitar trabalho já feito, mas o custo real de um cache é memória, e o resumo não diz quanto espaço as faixas ocupam nem qual política despeja as antigas.

Há ainda o limite estrutural da abordagem, que não é defeito e sim definição: um índice query-driven não ajuda a primeira execução, e não ajuda um predicado que nunca apareceu. Ele acelera repetição. Numa carga genuinamente ad hoc, o predicate cache não tem o que oferecer.

onde isso aparece hoje

O trabalho foi apresentado no SIGMOD 2024 e implementado como protótipo dentro do Amazon Redshift — protótipo, e o resumo é explícito nisso. Ele pertence à mesma linha de publicações em que a equipe do Redshift descreve como o sistema se adapta ao comportamento observado dos clientes em vez de exigir configuração: Amazon Redshift Re-invented estabelece a arquitetura, Stage: Query Execution Time Prediction in Amazon Redshift prevê o custo de uma query a partir do histórico e Intelligent Scaling in Amazon Redshift dimensiona o cluster pela carga. Predicate caching é a mesma tese aplicada ao acesso a dados: a carga de trabalho é a especificação.

O contraponto conceitual está em Designing Access Methods: The RUM Conjecture, que formaliza o triângulo entre custo de leitura, custo de escrita e espaço. Um índice que se paga com trabalho já realizado e ocupa pouco não escapa do triângulo — ele escolhe uma posição específica dentro dele, e paga em cobertura: só sabe sobre o que já foi perguntado.

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