support clients /

Optimiser le temps d’execution d’un tri sur son poste personnel

Un poste de travail standard n'a pas la même puissance qu'un serveur et il arrive qu'un tri ne puisse pas être réalisé ou bien qu'il soit très lent.
Cet article présente quelques astuces qui vous permettront de gagner du temps en tirant le meilleur parti de la PROC SORT.

Augmenter la valeur de l'option SORTSIZE

Par défaut SAS alloue 64Mo pour l'opération de tri. Afin de donner à SAS la possibilité d'utiliser plus de mémoire, il faut modifier l'option SORTSIZE=n (n étant exprimé en Mo ou Go).
Exemple pour laisser SAS utiliser 256Mo :
OPTIONS SORTSIZE=256M ;

Pour information, la valeur de SORTSIZE sera au maximum égale à la valeur de l'option REALMEMSIZE, elle-même inférieure à la valeur de MEMSIZE.

Voici un tableau montrant les temps obtenus avec l'option par défaut et en laissant SAS utiliser toute la mémoire dont il peut disposer (SORTSIZE=max)

 
Défaut
(SORTSIZE=64Mo)
SORTSIZE=max
100000 obs *
9s
4s
1 million d'obs *
1mn17s
38s

* Table de 20 variables caractères de longueur 32, triée sur 3 variables.
(pour la configuration matérielle utilisée, Cf. Conclusion)

Changer la taille du tampon d'écriture des fichiers temporaires

L'utilisation d'un tampon permet de stocker une certaine quantité de données dans la mémoire avant de faire une écriture physique sur le disque.
Lors du tri d'une table trop volumineuse et qui ne tient pas en mémoire, on constate deux points :
- le tri multi-threadé (option THREADS) peut ne pas être plus performant qu'un tri classique, surtout dans le cas ou un seul disque est utilisé pour faire les lectures et écritures.
En effet, un tri multi-threadé permet de découper un tri en plusieurs processus. Chaque processus écrivant sur le même disque cela peut provoquer un goulot d'étranglement à ce niveau.
- l'option SORTSIZE a une influence très limitée sur la durée du tri (Cf tableau ci-dessous).

 
SORTSIZE=500Mo
SORTSIZE=64Mo
2 millions d'obs *
3mn49s
3mn57s
2 millions d'obs *
(multithreadé)
4mn44s
4mn59s

* Table de 20 variables caractères de longueur 32, triée sur 3 variables.

Dans ce cas, il est alors possible de jouer sur la taille des tampons.
L'option UBUFSIZE (non documentée) permet de modifier la taille du tampon pour les fichiers temporaires. Cette option ne sera active que pour des tris non multi-threadés, aussi pour que l'option soit utilisée, on ajoutera NOTHREAD au niveau des options. (Penser à repositionner l'option THREADS après le traitement)
Afin d'avoir de meilleures performances sur des tables volumineuses, on peut positionner cette valeur à 2Mo ou plus.

Exemple :  
 
• options sortsize=500M ubufsize=2M nothreads;

 
SORTSIZE=500Mo
SORTSIZE=64Mo
2 millions d'obs *
3mn28s
3mn33s

* Table de 20 variables caractères de longueur 32, triée sur 3 variables.


 • options sortsize=500M ubufsize=8M nothreads;

 
SORTSIZE=500Mo
2 millions d'obs *
3mn16s

* Table de 20 variables caractères de longueur 32, triée sur 3 variables. Réduire le nombre de variables

Le nombre de variables présentes dans la table influe directement sur la quantité de données à mettre en mémoire.
Lors du tri d'une table, il est alors important de ne conserver que les variables qui seront utilisées dans la suite du traitement. Pour cela il est nécessaire de filtrer la table en entrée de la PROC SORT. Par exemple la procédure suivante extrait uniquement 4 variables pour une certaine modalité via une clause where.

proc sort data=bigdata(where=(VAR1="CODE1837485")
keep=VAR1 VAR2 VAR3 VAR4);
by VAR1 VAR2 VAR3;
run;

 
Défaut
(SORTSIZE=64Mo)
SORTSIZE=max
100000 obs *
0,2s
0,2s
1 million d'obs *
25s
15s
2 millions d'obs *
34s
22s

* Table de 5 variables caractères de longueur 32, triée sur 3 variables.

On voit que les gains obtenus sont très importants, il ne faut donc pas négliger cet aspect et supprimer chaque variable inutile avant d'effectuer un tri.

Modifier l'emplacement des fichiers temporaires

Les fichiers temporaires des tris non multi-threadés sont par défaut stockés dans la WORK.
Si plusieurs disques physiques sont disponibles, il est alors préférable de stocker ces fichiers sur un disque différent. Ainsi ce ne sera pas toujours le même disque qui sera sollicité.
Pour cela il faut spécifier l'option UTILLOC dans le fichier sasv9.cfg.

-UTILLOC ("d:\temp" )

L'option TAGSORT

L'option TAGSORT permet de stocker beaucoup moins de données en mémoire. Seules les valeurs des variables listées dans l'instruction BY sont stockées.
Cette option permet de réduire la quantité de mémoire nécessaire pour faire un tri. En contre partie, il y aura beaucoup de lectures écritures et il faut également noter que le processeur sera sollicité à son maximum.
Attention : cette option peut impacter les performances du tri. Cependant elle autorise le tri de tables trop volumineuses pour le tri standard ou bien dans le cas ou la mémoire disponible est limitée.

proc sort data=bigdata(where=(VAR1="CANADA") keep=VAR1 VAR2 VAR3 VAR4) tagsort;
by VAR1 VAR2 VAR3;
run;

Conclusion

Pour une table qui peut être stockée directement en mémoire, les meilleures performances sont obtenues en positionnant l'option SORTSIZE=max (50% de gain de temps dans l'exemple présenté ici).
Si la table ne rentre pas en mémoire il peut être intéressant de modifier l'option UBUFSIZE et de désactiver le multithread (32% de gain de temps dans cet exemple).
Dans tout les cas de figure, la meilleure optimisation est de ne pas sélectionner les variables qui ne seront pas utiles pour la suite du traitement afin de limiter le volume de données à traiter.

Les valeurs d'options présentées ici donnent un bon point de départ pour commencer l'optimisation d'un tri. Il faut cependant garder à l'esprit que l'optimisation d'un tri est une opération qui peut donner des résultats variables d'une machine à une autre en fonction de sa configuration matérielle et de la nature de la table à trier. Ainsi, l'utilisation de plusieurs disques ou de disques plus rapides donnera l'avantage à un tri multithreadé ce qui n'est pas toujours le cas sur une station de travail personnelle classique semblable à celle utilisée pour ces tests et qui est dotée d'un seul disque.

Les tests réalisés ici ont été faits sur une station de travail ayant 2Go de mémoire, un processeur double cœur et un seul disque dur.

Annexe

Programme utilisé pour générer une table volumineuse :
%macro createtable(lib,nom,n,v,m,l);
/*lib=bibliothèque en sortie
nom=nom de la table
n=nombre d'observations
v=nombre de variables
m=nombre de modalités possibles
l=longueur de la chaine de caractères
*/
data &lib..&nom(drop=i);
do i=1 to &n;
%do i=1 %to &v;
var&i=put(md5(int(ranuni(1)*&m)),hex&l..);
%end;
output;
end;
run;
%mend;

Exemple d'appel de la macro pour créer dans la bibliothèque test une table d'un million d'observations, de 20 variables de longueur 32 ayant 5000 modalités:
%createtable(test,bigdata,1000000,20,5000,32);

Julien Fages  
Consultant Support Clients - SAS France