LesezeichenAbonnierenRSS-Feed abonnieren
mfab
Quartz | Level 8

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

 

 

4 ANTWORTEN 4
andreas_lds
Jade | Level 19

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.

 

mfab
Quartz | Level 8

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

FreelanceReinh
Jade | Level 19

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

mfab
Quartz | Level 8

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. Smiley (fröhlich)

Ich finde die Diskussionen in der Community sehr bereichernd!

 

Herzlichen Dank und viele Grüße

Michael

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

Diskussionsstatistiken
  • 4 Antworten
  • 1778 Aufrufe
  • 4 Kudos
  • 3 in Unterhaltung