Hallo zusammen,
ich habe die Anforderung, dass ich ein Dataset (longdat) in zwei Teile (longdat2, longdat3) aufsplitten muss, diese Teile dann separat verarbeite und hinterher das Ganze wieder zu einem Dataset zusammenfüge, welches das ursprüngliche Dataset (longdat) ersetzt.
Da es sich um eine recht große Datenmenge handelt, spielt hier die Performance natürlich eine Rolle.
In diesem Zusammenhang ist mir aufgefallen, dass ein Überschreiben des ursprünglichen Dataset mit anschließendem Proc Append schneller läuft, als ein SET-Statement mit zwei Tabellen.
Kann sich das jemand erklären?
Es müssen doch so oder so alle Sätze einmal neu geschrieben werden?!
/* Dummy-Daten erzeugen */
/* Hier mit hinreichender Menge, damit die Verarbeitungszeit etwas ansteigt und Varianzen bei der Verarbeitung oder Messungenauigkeiten nicht zu sehr das Ergebnis beeinflussen */
data longdat;
do i = 1 to 1000000000;
a = put(i, binary.);
output;
end;
run;
/* Aufteilen der Daten, anschließend könnten diese weiter verarbeitet werden. Diesen Schritt habe ich hier ausgelassen, da nicht relevant */
data longdat2 longdat3;
set longdat;
if mod(i,10) = 0 then output longdat2; else output longdat3;
run;
/* Variante 1 - Ersetzen des Originals zunächst mit einem Teil der Daten ... */
data longdat;
set longdat2;
run;
/* ... anschließend Append der restlichen Daten */
proc append base=longdat data=longdat3;
run;
/* Variante 2 - Ersetzen des Originals mit beiden Datasets in einem Schritt */
data longdat;
set longdat2 longdat3;
run;
Variante 1 ist schneller:
28 data longdat;
29 set longdat2;
30 run;
NOTE: There were 100000000 observations read from the data set WORK.LONGDAT2.
NOTE: The data set WORK.LONGDAT has 100000000 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 12.78 seconds
user cpu time 4.69 seconds
system cpu time 8.05 seconds
memory 499.37k
OS Memory 30880.00k
Timestamp 22.02.2018 02:36:28 nachm.
Step Count 4 Switch Count 61
Page Faults 0
Page Reclaims 47
Page Swaps 0
Voluntary Context Switches 191
Involuntary Context Switches 150
Block Input Operations 8
Block Output Operations 3152008
31
32 proc append base=longdat data=longdat3;
33 run;
NOTE: Appending WORK.LONGDAT3 to WORK.LONGDAT.
NOTE: There were 900000000 observations read from the data set WORK.LONGDAT3.
NOTE: 900000000 observations added.
NOTE: The data set WORK.LONGDAT has 1000000000 observations and 2 variables.
NOTE: PROCEDURE APPEND used (Total process time):
real time 36.35 seconds
user cpu time 1.48 seconds
system cpu time 34.79 seconds
memory 479.68k
OS Memory 30880.00k
Timestamp 22.02.2018 02:37:04 nachm.
Step Count 5 Switch Count 34
Page Faults 2
Page Reclaims 82
Page Swaps 0
Voluntary Context Switches 95
Involuntary Context Switches 139
Block Input Operations 792
Block Output Operations 28367528
Variante 2 dauert länger:
34
35 data longdat;
36 set longdat2 longdat3;
37 run;
NOTE: There were 100000000 observations read from the data set WORK.LONGDAT2.
NOTE: There were 900000000 observations read from the data set WORK.LONGDAT3.
NOTE: The data set WORK.LONGDAT has 1000000000 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 1:28.69
user cpu time 46.46 seconds
system cpu time 41.99 seconds
memory 700.81k
OS Memory 30880.00k
Timestamp 22.02.2018 02:38:33 nachm.
Step Count 6 Switch Count 164
Page Faults 0
Page Reclaims 31
Page Swaps 0
Voluntary Context Switches 461
Involuntary Context Switches 1016
Block Input Operations 0
Block Output Operations 31519512
Bevor jemand auf den Gedanken kommt: ich habe das Ganze mehrfach und auch mit umgekehrter Reihenfolge ausprobiert, das SET-Statement ist immer langsamer.
Weiterhin wäre die Frage, ob ich ein neues Schreiben der Daten verhindern kann:
data longdat;
set longdat2;
run;
Hier werden die Daten von longdat2 alle nochmals verarbeitet.
Stattdessen würde ich lieber ein Proc Delete data=longdat machen und anschließend ein "rename" von longdat2 zu longdat ohne die Daten neu zu schreiben. Lässt SAS das irgendwie zu?
Interessant wäre hier auch, ob das mit SAS7BDAT-Dateien geht oder im SPDS. Wir haben Beides im Einsatz.
Herzlichen Dank - ich bin gespannt auf die Rückmeldungen - und viele Grüße
Michael
Ich fange mal unten an:
Stattdessen würde ich lieber ein Proc Delete data=longdat machen und anschließend ein "rename" von longdat2 zu longdat ohne die Daten neu zu schreiben. Lässt SAS das irgendwie zu?
Sollte so funktionieren:
proc delete data=longdat;
run;
proc datasets;
change longdat2 = longdat;
run;quit;
Und jetzt zur interessanten Frage:
In diesem Zusammenhang ist mir aufgefallen, dass ein Überschreiben des ursprünglichen Dataset mit anschließendem Proc Append schneller läuft, als ein SET-Statement mit zwei Tabellen.
Kann sich das jemand erklären?
Es müssen doch so oder so alle Sätze einmal neu geschrieben werden?!
Bei SET wird jede Beobachung in den PDV geladen und dann geschrieben, mit proc append gibt es afaik den Umweg über den PDV nicht, die Daten werden Blockweise (?) gelesen und geschrieben ,daher ist der Weg signifikant schneller.
Hallo @andreas_lds,
super, herzlichen Dank!
Das ist genau das, was ich wissen wollte. Mir war nicht klar, dass das Append den PDV "umgehen" kann. Ich dachte, der PDV wird immer erzeugt und verwendet.
Das hätte ich natürlich auch hier nachlesen können - sorry - hatte ich nicht dran gedacht.
Da ist auch aufgeführt, dass SAS unter Umständen keine Blockverarbeitung macht. Bleibt also noch für mich zu testen, ob das im Produktivcode sich so gut mit dem "compress" verträgt.
Die schnellste Verarbeitung für die obige Aufgabenstellen habe ich nun, wenn ich das größere Dataset umbenenne und anschließend das kleine Dataset appende. Läuft sehr flüssig:
proc delete data=longdat;
run;
proc datasets;
change longdat3 = longdat;
run;quit;
proc append base=longdat data=longdat2;
run;
Ganz herzlichen Dank und viele Grüße
Michael
Hallo Michael,
vielen Dank für den interessanten Performance-Vergleich. In der Tat scheinen die von PROC APPEND verwendeten Methoden, "Fast-Append Method" und "Block I/O Method", wie von Andreas angedeutet und in der Dokumentation zu PROC DATASETS beschrieben (siehe die beiden Links), gerade bei großen Datasets erheblich schneller zu sein als das SET-Statement. Auch fallen ja z. B. die automatischen Variablen _N_ und _ERROR_ weg, die im Datastep als Overhead erzeugt werden.
Wenn die System-Option MSGLEVEL=I gesetzt ist, werden die o. g. Methoden auch im Log dokumentiert (oder auch die Gründe, warum sie nicht verwendet werden konnten -- sicher nützlich, wenn andere Engines wie die SPD-Engine getestet werden):
INFO: Engine's fast-append process in use. INFO: 16:26:32 Reading DATA file, updating BASE file INFO: Starting data set size is 24619 pages INFO: Engine's block-read method is in use. INFO: Engine's block-write method is in use.
Mit PROC DATASETS kann man das Löschen, Umbenennen und Anhängen in einem Schritt durchführen:
proc datasets lib=work nolist;
delete longdat;
change longdat2=longdat;
append base=longdat new=longdat3;
quit;
Beste Grüße
Reinhard
Hallo Reinhard, (@FreelanceReinh)
vielen Dank. Das ist ja eine sehr elegante Lösung.
Proc Datasets kommt bei uns bisher kaum zum Einsatz - da sollte ich mich mal etwas einlesen. Aktuell läuft die Verarbeitung auch in unterschiedlichen Bibliotheken, daher ist das wahrscheinlich schon mit dem "proc datasets change" so eine Sache... aber vielleicht passe ich einfach unseren Prozess auf eine Verarbeitung in der gleichen Bibliothek an oder ich finde noch etwas in der Proc Datasets Beschreibung.
Alternativ werde ich wahrscheinlich auf sowas wie hier ausweichen:
data longdat;
set longdat2;
stop;
run;
proc append base=longdat data=longdat2;
run;
proc append base=longdat data=longdat3;
run;
Nichtsdestotrotz konnte ich wieder meinen Horizont erweitern.
Ich finde die Diskussionen in der Community sehr bereichernd!
Herzlichen Dank und viele Grüße
Michael
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!