Comparaison des performances de C et Rust pour les extensions d'analyse numérique SQLite
Simon Willison a comparé les implémentations en C et en Rust d'une extension `parse_number()` pour SQLite, constatant que le code C optimisé atteignait 16 à 19 ns par ligne.
Traduit automatiquement depuis l’original en anglais.
Le développeur Simon Willison a publié un benchmark technique le 8 novembre 2026, comparant les performances et la complexité du développement d'une extension SQLite personnalisée en C versus en Rust. L'étude portait sur une fonction parse_number() conçue pour nettoyer des données textuelles désordonnées afin de les convertir en valeurs numériques, révélant qu'une implémentation C hautement optimisée pouvait surpasser les équivalents Rust en vitesse brute tout en conservant une empreinte binaire nettement plus réduite.
Ce qui s'est passé
Willison a lancé l'expérience lors d'une promenade avec son chien, curieux des différences pratiques entre l'écriture d'une extension SQLite en C ou en Rust. Il a utilisé un assistant IA pour générer des prototypes initiaux dans les deux langages, visant à créer une fonction capable de supprimer les symboles monétaires, les virgules et les signes de pourcentage de chaînes comme -$1,234.56 ou '12.5%'. L'objectif était de renvoyer une valeur numérique valide pour la sommation et le tri, ou NULL si l'entrée ne pouvait pas être analysée. La comparaison initiale a montré que les extensions Rust étaient plus volumineuses mais étonnamment plus rapides que l'implémentation C naïve, qui reposait sur la fonction strtod de la bibliothèque standard.
Pour combler l'écart de performance, Willison a demandé à l'IA d'écrire une fonction d'analyse C personnalisée avec un chemin rapide compact, contournant les appels lents de la bibliothèque standard pour la gestion des décimales. Cette version C optimisée a réduit l'écart et a finalement surpassé les implémentations Rust en vitesse. Les résultats finaux ont démontré que le nouveau code C traitait les données mixtes en 19 nanosecondes par ligne, contre 41 à 46 nanosecondes pour les versions Rust. L'expérience s'est conclue par la génération, par l'IA, d'un rapport de recherche complet formaté pour le dépôt public de Willison, documentant le code, les tests et les métriques de performance.
Détails clés
- L'extension C optimisée a atteint un temps de traitement de 16 à 19 nanosecondes par ligne, soit environ deux fois plus vite que les versions Rust.
- La taille des fichiers différait considérablement : l'extension C pesait 14 Ko, tandis que les versions Rust variaient de 298 Ko à 321 Ko.
- Le code C initial était plus lent sur les décimales en raison de sa dépendance à
strtod, mais un chemin rapide personnalisé a résolu ce goulot d'étranglement. - Les quatre implémentations ont réussi 8 millions de vérifications de fuzzing, garantissant un comportement cohérent et précis face aux cas limites.
- L'implémentation Rust utilisant
rusqlitea pris 46 ns pour les données mixtes, tandis quesqlite-loadable-rsa pris 41 ns. - L'implémentation C finale traitait les entiers en 16 ns et les décimales en 18 ns, surpassant les 32-36 ns et 47-55 ns respectifs de Rust.
Contexte
SQLite est un moteur de base de données embarqué largement utilisé qui permet aux développeurs d'étendre ses fonctionnalités via des fonctions personnalisées écrites dans des langages compilés comme C ou Rust. Ces extensions s'exécutent directement au sein du processus de la base de données, ce qui les rend idéales pour les tâches de transformation de données à haute performance, telles que le nettoyage des enregistrements importés. Lors du choix d'un langage pour ces extensions, les développeurs doivent souvent équilibrer la facilité de développement et la sécurité mémoire par rapport à la vitesse d'exécution brute et à la taille du binaire. C offre une surcharge minimale et des binaires très petits, mais nécessite une gestion manuelle de la mémoire, tandis que Rust fournit de fortes garanties de sécurité au prix de binaires plus volumineux et de caractéristiques d'exécution potentiellement différentes.
La fonction parse_number() répondait à un problème courant d'ingénierie des données : la conversion de chaînes formatées pour les humains en nombres lisibles par machine. Les fonctions SQL standard comme replace() peuvent supprimer des caractères, mais sont souvent lentes lorsqu'elles sont appliquées ligne par ligne sur de grands jeux de données. Les extensions personnalisées contournent certaines de ces surcharges en opérant plus près du métal. Cependant, écrire des analyseurs efficaces en C nécessite une optimisation minutieuse pour éviter les pièges des fonctions de conversion généralistes, qui peuvent ne pas gérer efficacement les particularités de formatage spécifiques.
Pourquoi c'est important
Pour les équipes gérant des bases de données auto-hébergées ou développant des applications intensives en données, ce benchmark met en évidence les compromis tangibles entre la commodité de développement et l'efficacité opérationnelle. Bien que Rust offre une expérience de développement plus sûre et des outils robustes, la pénalité de performance dans ce micro-benchmark spécifique était significative. Pour les pipelines d'ingestion de données à haut volume où chaque nanoseconde compte, la capacité d'extraire la performance maximale de C peut réduire les coûts d'infrastructure et améliorer le débit. Cependant, cela implique la responsabilité de gérer manuellement la sécurité mémoire et les bugs potentiels.
L'étude souligne également le rôle croissant des assistants IA dans la programmation système de bas niveau. En exploitant l'IA pour générer et optimiser du code C complexe, les développeurs peuvent atteindre des niveaux de performance qui nécessiteraient autrement une expertise approfondie en programmation système. Cela démocratise l'accès aux extensions de bases de données hautes performances, permettant aux petites équipes de mettre en œuvre des optimisations personnalisées sans embaucher d'ingénieurs C spécialisés. Cela suggère que la barrière à l'entrée pour écrire des plugins de bases de données efficaces diminue, à condition de savoir guider efficacement les outils.
Que pouvez-vous faire
- Évaluez vos pipelines actuels de nettoyage de données pour identifier les goulots d'étranglement où des extensions SQLite personnalisées pourraient remplacer des fonctions SQL plus lentes.
- Envisagez d'utiliser C pour les extensions critiques en termes de performance si votre équipe dispose de l'expertise nécessaire pour gérer la sécurité mémoire et effectuer des tests rigoureux.
- Utilisez Rust pour les extensions où la vitesse de développement, la sécurité mémoire et la maintenabilité sont des priorités supérieures à la performance brute au niveau de la nanoseconde.
- Mettez en œuvre des tests de fuzzing complets pour toute logique d'analyse personnalisée afin de garantir qu'elle gère gracieusement les entrées inattendues ou malformées.
- Effectuez des benchmarks sur vos cas d'utilisation spécifiques plutôt que de vous fier à des hypothèses générales, car les performances peuvent varier en fonction de la distribution des données et du matériel.
- Exploitez les outils IA pour prototyper et optimiser le code de bas niveau, mais vérifiez toujours la sortie générée par des tests rigoureux et une revue de code.



