ProgrammationDéveloppeur Backend

Comment réaliser le calcul des totaux cumulés dans SQL sans fonctions de fenêtre, en tenant compte de la performance sur des milliers ou des millions de lignes ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Le calcul des totaux cumulés et des sommes courantes a traditionnellement été résolu dans SQL par le biais de fonctions de fenêtre (par exemple, SUM() OVER(ORDER BY ...)), cependant, dans les versions plus anciennes ou simplifiées des SGBD, seules les sous-requêtes et les regroupements sont disponibles. Historiquement, les architectes de bases de données cherchaient des solutions alternatives jusqu'à l'apparition de la norme SQL:2003 avec le soutien des fonctions de fenêtre.

Problème — en l'absence de fonctions de fenêtre, il est nécessaire de calculer explicitement la somme de toutes les valeurs précédentes pour chaque ligne, ce qui entraîne des requêtes imbriquées O(N^2) pour des ensembles de données suffisamment grands, à moins d'appliquer des astuces.

Solution:

On utilise généralement des sous-requêtes corrélées ou des tables temporaires avec mise à jour des valeurs :

Exemple de code :

-- Somme cumulée par requête corrélée SELECT t1.id, t1.amount, ( SELECT SUM(t2.amount) FROM transactions t2 WHERE t2.id <= t1.id ) AS running_total FROM transactions t1 ORDER BY t1.id; -- Via une table temporaire avec mise à jour manuelle des valeurs CREATE TEMPORARY TABLE temp_running (id INT, amount INT, running_total INT); -- On parcourt les lignes avec du code externe (par exemple, pl/pgsql), en ajoutant la somme séquentiellement

Caractéristiques clés :

  • La méthode fonctionne uniquement s'il existe un critère de tri unique (id, date de production)
  • La sous-requête corrélée évolue mal — croissance exponentielle du temps d'exécution
  • Pour de grands volumes de données, il est plus logique d'utiliser ETL avec agrégation en dehors de SQL ou avec des outils procéduraux

Questions pièges.

Fournit-elle un tri garanti par ORDER BY dans une sous-requête corrélée ?

Non — la sous-requête n'influence pas nécessairement le résultat lui-même. Le tri de l'ensemble final est toujours défini de l'extérieur dans la requête principale : le total dépend uniquement de la filtration par WHERE.

Peut-on paralléliser le calcul de la somme cumulée avec cette approche ?

Non — l'ordre est très important, surtout lors de calculs dépendant des lignes précédentes, ce qui rend une simple parallélisation impossible dans un SQL ordinaire.

Pourquoi la sous-requête corrélée est-elle si lente avec un grand nombre de lignes ?

Parce que pour chaque ligne, la somme est recalculée sur l'ensemble des lignes précédentes. Cela entraîne O(N^2) opérations. Sur un échantillon de 100 000 lignes, cela peut déjà prendre des minutes, voire des heures.

Erreurs typiques et anti-modèles

  • Filtrage incorrect par id au lieu de la date réelle — les sommes « sautent » sur les trous dans l'id
  • Tentative d'addition sans ordonnancement des données
  • Utilisation de cette approche pour d'énormes tables, lorsque ETL ou un traitement partitionné est nécessaire

Exemple de la vie réelle

Cas négatif

Un analyste a calculé le revenu cumulé quotidien par date via une sous-requête corrélée, alors que des id supprimés apparaissaient parfois dans la table (trous). La somme finale présentait des chutes brusques et dépendait non pas de la date, mais de l'ordre des id.

Avantages:

  • Fonctionne pour de petits ensembles, pas besoin de fonctions de fenêtre

Inconvénients:

  • Données incorrectes, calcule de manière inattendue
  • Support compliqué

Cas positif

Un ingénieur a déplacé le traitement de la somme cumulée dans un script ETL (Python/pandas), puis a téléchargé les valeurs finales dans une table distincte, synchronisant uniquement les nouvelles entrées. Les totaux étaient toujours concordants par date, le code fonctionnait rapidement et avec des millions d'enregistrements.

Avantages:

  • Fiabilité, possibilité de recalcul sans temps d'arrêt
  • Support de grands volumes

Inconvénients:

  • Paysage plus complexe — nécessite des outils externes de traitement