LanzamientoAnálisis · En radarSimon Willison→ original

Simon Willison reduce con Claude el análisis de números en SQLite de 67 a 19 ns

Un importe como «-$1,234.56» en un CSV necesita una limpieza antes de poder sumarlo en SQLite. Simon Willison pidió a Claude que comparara extensiones en C y Rust para esta tarea: las primeras versiones en Rust fueron más rápidas, aunque ocupaban bastante más espacio. Tras sustituir el analizador estándar de C, el tiempo de procesamiento por fila con datos mixtos bajó de 67 a 19 ns, frente a los 41–46 ns de Rust.

Procesado por IA desde Simon Willison; editado por Hamidun News
Simon Willison reduce con Claude el análisis de números en SQLite de 67 a 19 ns
Fuente: Simon Willison. Collage: Hamidun News.
Escuchar artículo
Ficha técnica y cifras clave
ParámetroDatos
Fuente originalSimon Willison ↗
Editor jefe
Dato clave #1La extensión en C ocupaba 14 KB; las versiones en Rust, 298 y 321 KB.
Dato clave #2Las mediciones abarcaron 2 millones de filas; el resultado depende de la composición de los datos.
Dato clave #3Antes de elegir un lenguaje, comprueba qué función consume el tiempo.

Exportas pagos a un CSV, los cargas en SQLite y en la columna de importes aparece «-$1,234.56». Para una persona es un número; para la base de datos, una cadena de texto que hay que analizar antes de sumar y ordenar. Simon Willison decidió comprobar lo difícil que sería añadir una función parse_number() para esta tarea y encargó a Claude que comparara implementaciones en C y Rust.

El resultado fue un experimento de ingeniería pequeño, pero útil. Al principio, Rust ganó en velocidad y C en tamaño de la extensión. Después, Willison pidió sustituir la función que analizaba los números en C y la situación cambió: con datos mixtos, el tiempo de procesamiento por fila bajó de 67 a 19 nanosegundos. La enseñanza práctica está en cómo un fragmento concreto de código puede cambiar el resultado de una comparación entre lenguajes.

Una función SQL en lugar de limpiar los datos en cada consulta

La tarea de parse_number() es sencilla: eliminar de una cadena las comas, los símbolos monetarios y el signo de porcentaje, tener en cuenta un posible signo menos inicial y devolver un valor numérico. Si la cadena no se puede interpretar, la función debe devolver NULL. Este comportamiento permite trasladar la limpieza repetitiva a una extensión de SQLite y utilizar después el resultado en los cálculos.

Por ejemplo, al eliminar el símbolo del dólar y el separador de miles de «-$1,234.56», se obtiene -1234.56. A continuación, ese valor puede sumarse a otros pagos u ordenarse como un número. El desarrollador no tiene que volver a montar una cadena de sustituciones de texto en cada consulta.

Los porcentajes requieren reglas propias. En su petición original, Willison propuso eliminar el signo de porcentaje. Pero cada producto debe decidir si «12.5%» representa el número 12.5 o la fracción 0.125. De esa decisión depende que los cálculos posteriores sean correctos. La rapidez al analizar una cadena no toma esa decisión por el equipo.

Por qué Rust fue más rápido al principio

Claude preparó versiones de la extensión en C y con dos bibliotecas de Rust: rusqlite y sqlite-loadable-rs. Según Willison, la extensión compilada en C ocupaba 14 KB. Las versiones en Rust ocupaban 321 y 298 KB, respectivamente. Para una pequeña utilidad integrada, esa diferencia puede ser relevante.

Sin embargo, la primera versión en C era más lenta. Con datos mixtos, su coste adicional de procesamiento era de 67 ns por fila, mientras que las versiones en Rust registraban 46 y 41 ns. Willison atribuyó la diferencia al análisis de números: el mecanismo utilizado en Rust era más rápido que la función estándar strtod de C.

La siguiente petición a Claude fue más específica: escribir una función propia en C para analizar números decimales que pudiera igualar o superar a Rust. Tras esa sustitución, la versión en C registró 19 ns con datos mixtos, 16 ns con enteros y 18 ns con fracciones decimales.

Como referencia, con fracciones decimales la versión original en C necesitaba 106 ns, frente a los 55 y 47 ns de las versiones en Rust. Todas las mediciones citadas corresponden a un experimento con dos millones de filas. Se trata del coste adicional de procesamiento por fila, por lo que estas cifras no pueden trasladarse directamente al tiempo de ejecución de una consulta SQL completa.

Qué comprobar antes de utilizarlo

El experimento muestra por qué elegir un lenguaje a partir de un único benchmark puede llevar fácilmente a una decisión precipitada. Aquí, sustituir una sola función cambió sustancialmente el resultado. En una tarea propia, resulta más útil identificar primero la operación costosa y después comparar alternativas con los mismos datos y los mismos requisitos para el resultado.

La mejora de velocidad tampoco demuestra por sí sola que un analizador propio pueda sustituir por completo al estándar. Antes de utilizarlo, conviene comprobar los formatos admitidos, los valores muy grandes, el redondeo, los espacios en blanco y las cadenas que contienen caracteres basura. Si el producto acepta importes de distintos países, también necesitará reglas para la coma decimal y los separadores de miles. Son aspectos que deben verificarse en la implementación, no defectos demostrados del código publicado.

Willison también pidió a Claude que documentara la investigación y publicó el resultado en el repositorio simonw/research. Para los desarrolladores, es un punto de partida: repetir las mediciones con sus propios datos exportados, comprobar la corrección y solo entonces elegir una implementación. En este caso, Claude ayudó a pasar rápidamente de una idea a varias alternativas medidas; su idoneidad sigue teniendo que evaluarse según los requisitos del sistema concreto.

Historia

Preguntas frecuentes sobre la noticia

¿Qué se sabe sobre Una función SQL en lugar de limpiar los datos en cada consulta?

La tarea de parse_number() es sencilla: eliminar de una cadena las comas, los símbolos monetarios y el signo de porcentaje, tener en cuenta un posible signo menos inicial y devolver un valor numérico. Si la cadena no se puede interpretar, la función debe devolver NULL. Este comportamiento permite trasladar la limpieza repetitiva a una extensión de SQLite y utilizar después el resultado en los cálculos. Por ejemplo, al eliminar el símbolo del dólar y el separador de miles de «-$1,234.56», se obtiene -1234.56.

¿Qué se sabe sobre Por qué Rust fue más rápido al principio?

Claude preparó versiones de la extensión en C y con dos bibliotecas de Rust: rusqlite y sqlite-loadable-rs. Según Willison, la extensión compilada en C ocupaba 14 KB. Las versiones en Rust ocupaban 321 y 298 KB, respectivamente. Para una pequeña utilidad integrada, esa diferencia puede ser relevante. Sin embargo, la primera versión en C era más lenta. Con datos mixtos, su coste adicional de procesamiento era de 67 ns por fila, mientras que las versiones en Rust registraban 46 y 41 ns.

¿Qué se sabe sobre Qué comprobar antes de utilizarlo?

El experimento muestra por qué elegir un lenguaje a partir de un único benchmark puede llevar fácilmente a una decisión precipitada. Aquí, sustituir una sola función cambió sustancialmente el resultado. En una tarea propia, resulta más útil identificar primero la operación costosa y después comparar alternativas con los mismos datos y los mismos requisitos para el resultado. La mejora de velocidad tampoco demuestra por sí sola que un analizador propio pueda sustituir por completo al estándar.

ZK
Zhemal Khamidun — CPO de Alpina Digital, product manager de AlpinaGPT. Crea productos de IA desde 2019. Hamidun News es un proyecto personal que creció hasta ser un agregador en producción con más de 6.000 lectores.
✦ 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
¿Qué te parece?
Cargando comentarios…