Lors de la transition vers SAS© Viya™, une question revient fréquemment chez les développeurs : pourquoi un code semble-t-il beaucoup plus rapide dans CAS, alors que dans d'autres cas, le gain est moins évident ? Plus important encore, pourquoi certains codes logiques, qui fonctionnaient parfaitement sous SAS© 9, produisent-ils des résultats différents dans CAS ?
Cet article explore les mécanismes sous-jacents qui distinguent le moteur traditionnel SAS© (SMP) du moteur distribué CAS (MPP), en se concentrant sur le DATA step.
1. La Vitesse : In-Memory et E/S Disque
L'un des avantages les plus évidents de CAS est le traitement en mémoire (In-Memory).
SAS© Classique (SAS© 9) : Le traitement implique souvent des lectures et écritures sur le disque dur. Même si le processeur est rapide, le goulot d'étranglement est souvent l'étape d'écriture (I/O).
CAS : Les données résident en mémoire vive (RAM). L'élimination des étapes d'écriture sur disque accélère considérablement le temps d'exécution global.
C'est souvent ce qui explique qu'un code générant de volumineuses données (comme une boucle créant des millions de lignes avec des calculs) s'exécute plus vite dans CAS : le temps gagné ne vient pas uniquement du calcul CPU, mais de l'absence d'écriture physique sur le disque.
2. Le Piège du "Single Thread" (Monothread)
Cependant, il est crucial de noter que CAS n'est pas magique. Tout ne s'exécute pas automatiquement en parallèle.
Prenons l'exemple d'un DATA step qui génère des données sans table en entrée (par exemple, une boucle DO de 1 à 5 millions pour créer des données simulées) :
Dans ce cas précis, CAS va exécuter ce code sur un seul thread (monothread). Le journal (log) affichera d'ailleurs une note explicite :
NOTE: The DATA step has no input data set and will run in a single thread.
Dans un scénario purement monothread, il arrive que le moteur SAS© 9 classique soit plus efficace et même plus rapide que CAS, car il a moins de "surcoût" (overhead) de gestion système que le moteur distribué. La puissance de CAS réside dans la distribution ; sans distribution, ce gain peut s'annuler.
3. Le Changement de Paradigme : Parallélisme et Partitionnement
La véritable différence architecturale apparaît lorsque le DATA step lit une table distribuée. CAS divise les données en blocs et les répartit sur plusieurs threads (et potentiellement plusieurs nœuds/machines).
Cela introduit des changements comportementaux majeurs pour certaines instructions historiques de SAS©.
Dans SAS© 9, l'instruction RETAIN conserve une valeur d'une observation à la suivante. Dans CAS, cette conservation se fait au sein d'un même thread. Une valeur retenue dans le "Thread 1" n'est pas visible par le "Thread 2".
Le piège du END=EOF
C'est sans doute le piège le plus fréquent. Dans SAS© classique, la condition if eof; ne se déclenche qu'une seule fois, à la toute fin de la table.
Dans un environnement distribué (multi-thread), la logique change :
Si vous exécutez ce code dans CAS avec plusieurs threads :
Vous n'obtiendrez pas une seule ligne, mais autant de lignes qu'il y a de threads actifs. Si votre session utilise 36 threads, vous aurez 36 observations en sortie, chacune représentant la dernière ligne traitée par ce thread spécifique.
Pour obtenir un total global, une étape d'agrégation supplémentaire (post-traitement) est souvent nécessaire.
4. Compatibilité des Fonctions
Enfin, lors de la migration de code, il faut garder à l'esprit que toutes les fonctions SAS© ne sont pas portées dans CAS. Si une fonction n'est pas supportée nativement par le moteur CAS, le système peut parfois rapatrier les données vers le serveur de calcul (Compute Server) pour effectuer le traitement, ce qui annule les bénéfices de performance du traitement distribué. Il est recommandé de vérifier la documentation pour s'assurer que les fonctions utilisées sont "CAS-enabled".
Le passage de SAS© 9 à CAS ne se résume pas à changer le nom de la LIBNAME.
Pour la performance : CAS excelle dans le traitement massif en mémoire et parallèle, mais peut être moins performant sur de petits volumes ou des tâches purement séquentielles (monothread).
Pour la logique : Les développeurs doivent adapter leur "carte mentale". Le concept de lecture séquentielle du début à la fin d'un fichier unique disparaît au profit d'un traitement par blocs indépendants.