SortieAnalyse · Sur le radarSimon Willison→ original

Simon Willison et Claude font passer l'analyse de nombres dans SQLite de 67 à 19 ns

Le montant « -$1,234.56 » issu d'un CSV doit être nettoyé avant de pouvoir être additionné dans SQLite. Simon Willison a demandé à Claude de comparer des extensions en C et en Rust pour cette tâche : les premières versions en Rust se sont révélées plus rapides, bien qu'elles occupent nettement plus d'espace. Après le remplacement de l'analyseur standard en C, le temps de traitement d'une ligne sur des données mixtes est passé de 67 à 19 ns, contre 41 à 46 ns pour Rust.

Traité par IA depuis Simon Willison ; édité par Hamidun News
Simon Willison et Claude font passer l'analyse de nombres dans SQLite de 67 à 19 ns
Source : Simon Willison. Collage: Hamidun News.
Écouter l'article
Fiche synthèse et chiffres clés
ParamètreDonnées
Source primaireSimon Willison ↗
Rédacteur en chef
Chiffre clé #1L'extension en C pesait 14 Ko, les variantes en Rust 298 et 321 Ko.
Chiffre clé #2Les mesures portaient sur 2 millions de lignes ; le résultat dépend de la composition des données.
Chiffre clé #3Avant de choisir un langage, vérifiez quelle fonction consomme le temps.

Vous avez exporté des paiements en CSV, les avez chargés dans SQLite, et la colonne des montants contient « -$1,234.56 ». Pour un humain, c'est un nombre ; pour la base, c'est une chaîne qu'il faut analyser avant de pouvoir additionner ou trier. Simon Willison a voulu vérifier s'il était difficile d'ajouter pour cela une fonction parse_number(), et a chargé Claude de comparer des implémentations en C et en Rust.

Il en est sorti une petite expérience d'ingénierie, mais utile. Au début, Rust l'a emporté sur la vitesse, et C sur la taille de l'extension. Puis Willison a demandé de remplacer la fonction d'analyse des nombres en C, et la donne a changé : sur des données mixtes, le temps de traitement d'une ligne est passé de 67 à 19 nanosecondes. L'enseignement pratique tient à la façon dont un seul segment de code peut modifier le résultat de la comparaison entre langages.

Une fonction SQL plutôt qu'un nettoyage dans chaque requête

La tâche de parse_number() est simple : retirer de la chaîne les virgules, les symboles monétaires et le signe pourcentage, tenir compte d'un moins initial et renvoyer la valeur numérique. Si la chaîne ne peut pas être analysée, la fonction doit renvoyer NULL. Ce comportement permet de sortir le nettoyage répétitif dans une extension SQLite, puis d'utiliser le résultat dans les calculs.

Par exemple, « -$1,234.56 » devient -1234.56 une fois le dollar et le séparateur de milliers supprimés. Cette valeur peut ensuite être additionnée à d'autres paiements ou triée comme un nombre. Le développeur n'a plus à reconstruire dans chaque requête une chaîne de remplacements de texte.

Les règles concernant les pourcentages méritent d'être définies à part. Dans sa requête initiale, Willison proposait de supprimer le signe pourcentage. Mais pour un produit donné, il faut décider si « 12.5% » signifie le nombre 12.5 ou la fraction 0.125. La justesse des calculs ultérieurs en dépend. Une analyse rapide de la chaîne ne prend pas cette décision à la place de l'équipe.

Pourquoi Rust s'est d'abord montré plus rapide

Claude a préparé des variantes de l'extension en C et avec deux bibliothèques Rust : rusqlite et sqlite-loadable-rs. D'après Willison, l'extension compilée en C pesait 14 Ko. Les variantes en Rust : respectivement 321 et 298 Ko. Pour un petit utilitaire embarqué, cet écart peut compter.

Toutefois, la première version en C était moins rapide. Sur des données mixtes, son surcoût de traitement était de 67 ns par ligne, contre 46 et 41 ns pour les variantes en Rust. Willison a attribué l'écart à l'analyse des nombres : le mécanisme utilisé en Rust était plus rapide que la fonction standard strtod du C.

La demande suivante à Claude était ciblée : écrire en C sa propre fonction d'analyse de nombres décimaux, capable de rattraper ou de dépasser Rust. Après ce remplacement, la variante en C a affiché 19 ns sur des données mixtes, 16 ns sur des entiers et 18 ns sur des fractions décimales.

À titre de comparaison, sur les fractions décimales, la version initiale en C nécessitait 106 ns, contre 55 et 47 ns pour les variantes en Rust. Toutes les mesures citées proviennent d'une expérience sur deux millions de lignes. Il s'agit du surcoût de traitement par ligne ; on ne peut donc pas transposer directement ces chiffres au temps d'exécution d'une requête SQL entière.

Ce qu'il faut vérifier avant l'utilisation

L'expérience montre pourquoi choisir un langage à partir d'un seul benchmark mène facilement à une décision hâtive. Ici, le résultat a sensiblement changé après le remplacement d'une seule fonction. Pour votre propre besoin, il vaut mieux d'abord identifier l'opération coûteuse, puis comparer les alternatives sur les mêmes données et avec les mêmes exigences sur le résultat.

Par ailleurs, l'accélération ne prouve pas qu'un analyseur maison remplace entièrement l'analyseur standard. Avant utilisation, il faut vérifier les formats admis, les très grandes valeurs, l'arrondi, les espaces et les chaînes parasites. Si le produit accepte des montants de différents pays, il faudra des règles distinctes pour la virgule décimale et les séparateurs de milliers. Ce sont des points de vérification de l'implémentation, et non des défauts avérés du code publié.

Willison a aussi demandé à Claude de mettre en forme l'étude et a publié le résultat dans le dépôt simonw/research. Pour un développeur, c'est un point de départ : refaire les mesures sur son propre export, vérifier la justesse, et seulement ensuite choisir l'implémentation. Dans cette histoire, Claude a permis de parcourir rapidement le chemin de l'idée à plusieurs variantes mesurées ; il faut malgré tout juger de leur adéquation selon les exigences du système concerné.

Dossier

Questions clés sur cet article

Que sait-on sur Une fonction SQL plutôt qu'un nettoyage dans chaque requête ?

La tâche de parse_number() est simple : retirer de la chaîne les virgules, les symboles monétaires et le signe pourcentage, tenir compte d'un moins initial et renvoyer la valeur numérique. Si la chaîne ne peut pas être analysée, la fonction doit renvoyer NULL. Ce comportement permet de sortir le nettoyage répétitif dans une extension SQLite, puis d'utiliser le résultat dans les calculs. Par exemple, « -$1,234.56 » devient -1234.56 une fois le dollar et le séparateur de milliers supprimés.

Pourquoi Rust s'est d'abord montré plus rapide?

Claude a préparé des variantes de l'extension en C et avec deux bibliothèques Rust : rusqlite et sqlite-loadable-rs. D'après Willison, l'extension compilée en C pesait 14 Ko. Les variantes en Rust : respectivement 321 et 298 Ko. Pour un petit utilitaire embarqué, cet écart peut compter. Toutefois, la première version en C était moins rapide. Sur des données mixtes, son surcoût de traitement était de 67 ns par ligne, contre 46 et 41 ns pour les variantes en Rust.

Que sait-on sur Ce qu'il faut vérifier avant l'utilisation ?

L'expérience montre pourquoi choisir un langage à partir d'un seul benchmark mène facilement à une décision hâtive. Ici, le résultat a sensiblement changé après le remplacement d'une seule fonction. Pour votre propre besoin, il vaut mieux d'abord identifier l'opération coûteuse, puis comparer les alternatives sur les mêmes données et avec les mêmes exigences sur le résultat. Par ailleurs, l'accélération ne prouve pas qu'un analyseur maison remplace entièrement l'analyseur standard.

ZK
Zhemal Khamidun — CPO d'Alpina Digital, product manager d'AlpinaGPT. Conçoit des produits IA depuis 2019. Hamidun News est un projet personnel devenu un agrégateur en production avec plus de 6 000 lecteurs.
✦ 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'en pensez-vous ?
Chargement des commentaires…