LançamentoAnálise · No radarSimon Willison→ original

Simon Willison usa Claude para reduzir de 67 para 19 ns a análise de números no SQLite

Um valor como “-$1,234.56” em um CSV precisa ser tratado antes de entrar em uma soma no SQLite. Simon Willison pediu ao Claude que comparasse extensões em C e Rust para essa tarefa: as primeiras versões em Rust foram mais rápidas, embora ocupassem consideravelmente mais espaço. Após a substituição do parser padrão em C, o tempo de processamento por linha com dados mistos caiu de 67 para 19 ns, contra 41–46 ns em Rust.

Processado por IA de Simon Willison; editado por Hamidun News
Simon Willison usa Claude para reduzir de 67 para 19 ns a análise de números no SQLite
Fonte: Simon Willison. Colagem: Hamidun News.
Ouvir artigo
Ficha técnica e números-chave
ParâmetroDados
Fonte originalSimon Willison ↗
Editor-chefe
Dado-chave #1A extensão em C ocupava 14 KB; as versões em Rust, 298 e 321 KB.
Dado-chave #2As medições abrangeram 2 milhões de linhas; o resultado depende da composição dos dados.
Dado-chave #3Antes de escolher a linguagem, verifique qual função consome o tempo.

Você exporta pagamentos para um CSV, carrega o arquivo no SQLite e encontra “-$1,234.56” na coluna de valores. Para uma pessoa, isso é um número; para o banco de dados, é uma string que precisa ser interpretada antes das operações de soma e ordenação. Simon Willison decidiu verificar a dificuldade de adicionar uma função parse_number() para essa tarefa e pediu ao Claude que comparasse implementações em C e Rust.

O resultado foi um experimento de engenharia pequeno, mas útil. De início, Rust ganhou em velocidade, e C, no tamanho da extensão. Depois, Willison pediu a substituição da função de análise de números em C, e o cenário mudou: com dados mistos, o tempo de processamento por linha caiu de 67 para 19 nanossegundos. A lição prática está em como um trecho específico de código pode mudar o resultado de uma comparação entre linguagens.

Uma função SQL em vez de tratar os dados em cada consulta

A tarefa de parse_number() é simples: remover vírgulas, símbolos monetários e sinais de porcentagem de uma string, considerar um eventual sinal de menos no início e retornar um valor numérico. Se a string não puder ser interpretada, a função deve retornar NULL. Esse comportamento permite transferir o tratamento repetitivo dos dados para uma extensão do SQLite e depois usar o resultado nos cálculos.

Por exemplo, ao remover o símbolo de dólar e o separador de milhares de “-$1,234.56”, o resultado é -1234.56. Esse valor pode então ser somado a outros pagamentos ou ordenado como um número. O desenvolvedor deixa de precisar montar novamente uma sequência de substituições de texto em cada consulta.

Porcentagens exigem regras próprias. No pedido original, Willison propôs remover o sinal de porcentagem. Mas cada produto precisa decidir se “12.5%” representa o número 12.5 ou a fração 0.125. A correção dos cálculos posteriores depende dessa decisão. A velocidade de interpretação de uma string, por si só, não toma essa decisão pela equipe.

Por que Rust foi mais rápido no início

Claude preparou versões da extensão em C e com duas bibliotecas de Rust: rusqlite e sqlite-loadable-rs. Segundo Willison, a extensão compilada em C ocupava 14 KB. As versões em Rust ocupavam 321 e 298 KB, respectivamente. Para um pequeno utilitário embarcado, essa diferença pode ser relevante.

No entanto, a primeira versão em C era mais lenta. Com dados mistos, seu custo adicional de processamento era de 67 ns por linha, enquanto as versões em Rust registravam 46 e 41 ns. Willison atribuiu a diferença à análise dos números: o mecanismo usado em Rust era mais rápido que a função padrão strtod de C.

O pedido seguinte ao Claude foi mais específico: escrever uma função própria em C para interpretar números decimais que pudesse igualar ou superar Rust. Após essa substituição, a versão em C registrou 19 ns com dados mistos, 16 ns com números inteiros e 18 ns com frações decimais.

Para comparação, com frações decimais a versão original em C precisava de 106 ns, enquanto as versões em Rust levavam 55 e 47 ns. Todas as medições citadas correspondem a um experimento com dois milhões de linhas. Elas representam o custo adicional de processamento por linha, portanto esses números não podem ser convertidos diretamente no tempo de execução de uma consulta SQL inteira.

O que verificar antes de usar

O experimento mostra por que escolher uma linguagem com base em um único benchmark pode facilmente levar a uma decisão precipitada. Aqui, substituir uma única função mudou bastante o resultado. Para uma tarefa própria, é mais útil identificar primeiro a operação que consome mais tempo e depois comparar alternativas com os mesmos dados e os mesmos requisitos para o resultado.

O ganho de velocidade, por si só, também não demonstra que um parser próprio substitui completamente o padrão. Antes de usá-lo, vale verificar os formatos aceitos, valores muito grandes, arredondamento, espaços em branco e strings com caracteres inválidos. Se o produto aceita valores de diferentes países, também serão necessárias regras para a vírgula decimal e os separadores de milhares. Esses são aspectos a verificar na implementação, e não falhas comprovadas do código publicado.

Willison também pediu ao Claude que documentasse a pesquisa e publicou o resultado no repositório simonw/research. Para os desenvolvedores, esse é um ponto de partida: repetir as medições com seus próprios dados exportados, verificar a correção e só então escolher uma implementação. Neste caso, Claude ajudou a avançar rapidamente de uma ideia para várias alternativas medidas; a adequação de cada uma ainda precisa ser avaliada de acordo com os requisitos do sistema específico.

História

Perguntas frequentes sobre a notícia

O que se sabe sobre Uma função SQL em vez de tratar os dados em cada consulta?

A tarefa de parse_number() é simples: remover vírgulas, símbolos monetários e sinais de porcentagem de uma string, considerar um eventual sinal de menos no início e retornar um valor numérico. Se a string não puder ser interpretada, a função deve retornar NULL. Esse comportamento permite transferir o tratamento repetitivo dos dados para uma extensão do SQLite e depois usar o resultado nos cálculos. Por exemplo, ao remover o símbolo de dólar e o separador de milhares de “-$1,234.56”, o resultado é -1234.56.

Por que Rust foi mais rápido no início?

Claude preparou versões da extensão em C e com duas bibliotecas de Rust: rusqlite e sqlite-loadable-rs. Segundo Willison, a extensão compilada em C ocupava 14 KB. As versões em Rust ocupavam 321 e 298 KB, respectivamente. Para um pequeno utilitário embarcado, essa diferença pode ser relevante. No entanto, a primeira versão em C era mais lenta. Com dados mistos, seu custo adicional de processamento era de 67 ns por linha, enquanto as versões em Rust registravam 46 e 41 ns.

O que verificar antes de usar?

O experimento mostra por que escolher uma linguagem com base em um único benchmark pode facilmente levar a uma decisão precipitada. Aqui, substituir uma única função mudou bastante o resultado. Para uma tarefa própria, é mais útil identificar primeiro a operação que consome mais tempo e depois comparar alternativas com os mesmos dados e os mesmos requisitos para o resultado. O ganho de velocidade, por si só, também não demonstra que um parser próprio substitui completamente o padrão.

ZK
Zhemal Khamidun — CPO da Alpina Digital, gerente de produto do AlpinaGPT. Cria produtos de IA desde 2019. O Hamidun News é um projeto pessoal que virou um agregador em produção com mais de 6.000 leitores.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
O que você acha?
Carregando comentários…