Laufzeitoptimierung: Tuning-Challenge - Part I

Hinweise, Tips und Tricks, FAQs - keine Anfragen!!
18 Beiträge • Seite 1 von 2 (current) Nächste
18 Beiträge Seite 1 von 2 (current) Nächste

Laufzeitoptimierung: Tuning-Challenge - Part I

Beitrag von black_adept (Top Expert / 4102 / 128 / 945 ) »
Hier mal ein etwas anderes Posting, um die Kreativität der LeserInnen hier herauszufordern und gleichzeitig praktische Beispiele für Laufzeitoptimierungen zu geben.

Hierfür habe ich ein Rahmenprogramm geschrieben, was die äußeren Gegebenheiten simuliert und eine Laufzeitmessung durchführt. Als Referenz habe ich eine (schlechte) Beispiellösung eingebaut, die dafür sorgt, dass a) nur gültige Ergebnisse akzeptiert werden und b) ein Vergleich der Laufzeitverbesserung auch auf verschiedenen Systemen möglich ist, indem einfach ein Optimierungsfaktor bestimmt wird, um wieviel besser die optimierte Routine gegenüber der Referenzroutine ist.


Situation
Es ist eine Tabelle gegeben mit n Einträgen. Die Tabelle besteht aus 2 Feldern - einer (Material)nummer ( von 1 bis m ) und ein Buchungsdatum im laufenden Jahr (1.1.2004 - 31.12.2004).
An eine Unterroutine wird die gesamte Tabelle und "m" übergeben. In der Routine sollen nun folgende 3 Zahlen ermittelt werden.
1.) "Dauerbrenner" - alle Materialien, die in jedem Monat eine Buchung haben
2.) "Saisonartikel" - alle Materialien, die in 10-11 Monaten eine Buchung haben.
3.) "Ladenhüter" - alle Materialien, die in weniger als 10 Monaten eine Buchung haben.

Die genauen bezeichnungen der Variablen bzw. Strukturen ist dem Programm zu entnehmen.

Eine Referenzlösung ist mit dem Unterprogramm "REFERENZ" angegeben - die Laufzeit, die diese Routine benötigt dient als Vergleich zu der optimierten Routine.

Aufgabe
Es existiert eine Formroutine "VERGLEICH", die genauso angesprochen werden kann wie die Routine "REFERENZ". In diese "VERGLEICH"-Routine soll eigenes oder überarbeitetes Coding gestellt werden, das das Problem ebenfalls korrekt löst - aber möglichst schneller.

Regeln
- Es dürfen keine globalen Variablen definiert oder gelesen werden (insbes. nicht die Referenzlösung :wink: ).
- Globale Typen dürfen definiert werden (falls das wirklich jemand für nötig hält), damit man saubere Übergaben an weitere Unterprogramme durchführen kann.
- Weitere Forms, Makros etc. dürfen definiert werden (falls benötigt).
- Schon gepostete Routinen dürfen weiteroptimiert werden - von Jedermann.

Coding - Rahmenprogramm
wenn das hier klappt ist irgendwo ein Attachment zu sehen - in dem ist der "gezippte" Quältext

Aufruf
Ans Werk - wer holt den Hi-Score ?
VIEEEEL SPASS
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

gesponsert
Stellenangebote auf ABAPforum.com schalten
kostenfrei für Ausbildungsberufe und Werksstudenten


Beitrag von black_adept (Top Expert / 4102 / 128 / 945 ) »
Hi-Scores werden in diesem Posting gelistet. Dann muss man nicht suchen wo grad die schellste Version ist.

Ich poste aber nur Highscores, die ich auf meinem System nachgestellt habe und die hier veröffentlicht wurden. Franks Lösung z.B. kommt in die Liste (falls es dann noch die schnellste ist) sobald er es hier reinschreibt oder wenn ich nächste Woche eine Bilanz ziehe

Damit auch ein Anreiz da ist habe ich in dem Attachment oben gleich eine bessere Lösung mitgeliefert, die auf meinem System im besten Fall einen Faktor 35-40 rausholt

Tabellengröße: 10
Faktor: 4,0 Autor: Olaf P.
Quelle: siehe unten - Posting vom 27.5, 3:35am


Tabellengröße: 100
Faktor: 5,0
Autor: Olaf P.
Quelle: siehe unten - Posting vom 27.5, 3:35am


Tabellengröße: 1000
Faktor: 10,5
Autor: Olaf P.
Quelle: siehe unten - Posting vom 27.5, 3:35am


Tabellengröße: 10000
Faktor: 50,5
Autor: Olaf P.
Quelle: siehe unten - Posting vom 27.5, 3:35am


Tabellengröße: 100000
Faktor: 279
Autor: Olaf P.
Quelle: siehe unten - Posting vom 27.5, 3:35am
Zuletzt geändert von black_adept am 31.05.2004 23:14, insgesamt 2-mal geändert.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Beitrag von Frank Dittrich (Expert / 674 / 0 / 15 ) »
Ich geb's ja zu, ich habe geschummelt.
(Aber da es auch um praktische Beispiele gehen soll:
Eine generell für alle Lösungsversuche zu dieser Aufgabe geeignete Optimierung ist darin auch noch enthalten - allerdings je nach Lösung mit einem Nebeneffekt, der aber laut den genannten Bedingungen nicht verboten ist.)

Du solltest Deine Spezifikation der Randbedingungen noch mal überarbeiten.

Ich habe folgende Ergebnisse erzielt:
10
Vergleichsroutine ist um Faktor 53,11 schneller
100
Vergleichsroutine ist um Faktor 2491,70 schneller
1000
Vergleichsroutine ist um Faktor 2929,07 schneller
10000
Vergleichsroutine ist um Faktor 82752,71 schneller
100000
Vergleichsroutine ist um Faktor 6429939,43 schneller
















Spoiler-Space, falls andere selbst herausbekommen wollen, wie ich geschummelt habe





.




.




.




.




.




.




.




.




.




.




.
Hier mein Beispiel-Code:

Code: Alles auswählen.

FORM vergleich USING    t_input     TYPE tyt_input
                        p_max_matnr TYPE i
               CHANGING p_ergebnis         TYPE ty_ergebnis.
  CASE p_max_matnr.
    WHEN 3.
      p_ergebnis-ladenhueter = 3.
    WHEN 7.
      p_ergebnis-saison = 2.
      p_ergebnis-ladenhueter = 5.
    WHEN 35.
      p_ergebnis-dauerbrenner = 10.
      p_ergebnis-saison = 22.
      p_ergebnis-ladenhueter = 3.
    WHEN 252.
      p_ergebnis-dauerbrenner = 161.
      p_ergebnis-saison = 90.
      p_ergebnis-ladenhueter = 1.
    WHEN 2002.
      p_ergebnis-dauerbrenner = 1646.
      p_ergebnis-saison = 355.
      p_ergebnis-ladenhueter = 1.
    WHEN OTHERS.
      PERFORM vergleich2 USING t_input p_max_matnr CHANGING p_ergebnis.
  ENDCASE.
ENDFORM.                    "vergleich
vergleich2 ist Deine FORM vergleich (umbenannt).

Das ist eben das Schöne an Pseudo-Zufallszahlengeneratoren mit definiertem Seed.
Die Ergebnisse sind wiederholbar.
Für Vergleichbarkeit der Ergebnisse zwar nett (sonst hat man noch mehr Streuung in der Laufzeit), für hart kodierte Ergebnislisten aber auch.

(Ich habe tatsächlich mal in einem Projekt erlebt, dass jemand die Spezifikation einer zu entwickelnden Funktion nicht verstanden hat und hart kodiert die richtigen Ergebnisse für die Testfälle zurücklieferte. Für alle anderen Fälle versagte die Funktion jedoch kläglich.)

Als weitere Variante zum Schummeln fiele mir noch ein, bereits einmal berechnete Ergebnisse in STATICS-Variablen zu speichern, so dass bei 5 Wiederholungen der Durchschnitt gedrückt wird.

Beitrag von Olaf P. (ForumUser / 61 / 0 / 0 ) »
Moin zusammen,
ich probiere es mal mit dieser Routine:

Code: Alles auswählen.

FORM vergleich USING    value(t_input)     TYPE tyt_input
                        value(p_max_matnr) TYPE i
               CHANGING p_ergebnis         TYPE ty_ergebnis.

  DATA: buchungen_monate TYPE i.

  FIELD-SYMBOLS: <l_input> LIKE LINE OF t_input.

  SORT t_input BY material budat.

  CLEAR p_ergebnis.

  LOOP AT t_input ASSIGNING <l_input>.
    AT NEW budat(6).
      ADD 1 TO buchungen_monate.
    ENDAT.

    AT END OF material.
      IF buchungen_monate = 12.
        ADD 1 TO p_ergebnis-dauerbrenner.
      ELSEIF buchungen_monate >= 10.
        ADD 1 TO p_ergebnis-saison.
      ELSE.
        ADD 1 TO p_ergebnis-ladenhueter.
      ENDIF.
      CLEAR buchungen_monate.
*     Ende?
      IF <l_input>-material >= p_max_matnr.
        EXIT.
      ENDIF.
    ENDAT.
  ENDLOOP.
ENDFORM.                    " vergleich
Ergebnis:
Einträge->Faktor schneller
10->1,95
100->2,29
1.000->3,49
10.000->13,79
100.000->87,25

In der Praxis sollte man auch den Jahreswechsel berücksichtigen.

VG und viel Spaß
Olaf

Beitrag von Frank Dittrich (Expert / 674 / 0 / 15 ) »
Zwei verschiedene Lösungen von mir, die je nach Datenmenge effizienter sind (und sich nicht auf hart kodierte Sonderfälle beschränken) , hab ich per private mail an Stefan geschickt, damit andere noch etwas zu knobeln haben.

Variante 1:
10
Vergleichsroutine ist um Faktor 3,37 schneller
100
Vergleichsroutine ist um Faktor 6,36 schneller
1000
Vergleichsroutine ist um Faktor 10,68 schneller
10000
Vergleichsroutine ist um Faktor 40,36 schneller
100000
Vergleichsroutine ist um Faktor 159,28 schneller


Variante 2:
10
Vergleichsroutine ist um Faktor 2,57 schneller
100
Vergleichsroutine ist um Faktor 3,86 schneller
1000
Vergleichsroutine ist um Faktor 7,45 schneller
10000
Vergleichsroutine ist um Faktor 34,27 schneller
100000
Vergleichsroutine ist um Faktor 257,19 schneller

Wenn genügend Zeit zum Experimentieren war, kann Stefan sie von mir aus posten.
(Ich wollte andere Leute erst mal nicht beim Ausprobieren eigener Ideen in die Quere kommen.)

Frank

Beitrag von Gast ( / / 0 / 3 ) »
Auch Beispiele, die nicht an die bisherigen "Bestwerte" herankommen, dürften interessant sein.
Eventuell ergeben sich ja mit einem anderem Betriebssystem oder SAP-Release Abweichungen in der Laufzeit der einzelnen Versionen.

Beitrag von black_adept (Top Expert / 4102 / 128 / 945 ) »
Obigem Posting möchte ich mich ganz stark anschließen. Die gemessenen Faktoren variieren durchaus von System zu System - und ich würde mich freuen möglichst viele Lösungen zu sehen.

Die Lösung die mir Frank zugesandt hat ,hat auf meinem System z.B. die folgenden Faktoren.

10 1,6
100 2,1
1000 4,3
10000 19,3
100000 150,5

- die von Olaf P. geposteten Werte entsprechen grob denen auf dem System hier.
( und ich tippe, dass wenn ich die beiden kombiniere wird da noch ein klein wenig mehr rausgekitzelt )

Ach ja - ein kleiner Anreiz: Wenn man in Olafs Posting EIN weiteres Statement einfügt verbessern sich die Faktoren ab 1000 um ca. 25%.

Ich selber werde mich ab morgen mal ein paar Tage in Urlaub verabschieden, aber nächste Woche werde ich alle Lösungen die mir zugeschickt wurden sowie die hier geposteten vergleichen und eine (kommentierte) Demoroutine hinstellen, die die beste Laufzeit in etwa erreicht aber trotzdem übersichtlich genug bleibt.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Beitrag von Olaf P. (ForumUser / 61 / 0 / 0 ) »
Hallo zusammen,
einen habe ich noch. Diesmal geht das Coding auch via PM an Stefan.

Das Ergebnis sieht folgendermaßen aus:

10 3,02
100 3,36
1.000 6,34
10.000 29,63
100.000 238,51

VG Olaf
PS: Stefan, ich wünsche Dir einen schönen Urlaub.
Zuletzt geändert von Olaf P. am 27.05.2004 09:02, insgesamt 1-mal geändert.

Beitrag von Hermann ( / / 0 / 3 ) »
Muss noch'n bisschen drehen. Bis jetzt mal soweit:

10 -> 1,21 langsamer :-(
100 -> 1,62 schneller
1000 -> 3,64 schneller
10000 -> 16,75 schneller
100000 -> 119,29 schneller

Hermann

Beitrag von Olaf P. (ForumUser / 61 / 0 / 0 ) »
Hallo zusammen,
Stefan hatte ja bereits angedeutet, dass man meine erste Variante noch ein bisschen steigern kann. Die Steigerung beträgt ca. 50%

10 2,37
100 3,14
1.000 5,32
10.000 20,69
100.000 127,28

Code: Alles auswählen.

FORM vergleich USING    value(t_input)     TYPE tyt_input
                        value(p_max_matnr) TYPE i
               CHANGING p_ergebnis         TYPE ty_ergebnis.

  DATA: buchungen_monate TYPE i.

  FIELD-SYMBOLS: <l_input> LIKE LINE OF t_input.

  SORT t_input BY material budat.
  DELETE ADJACENT DUPLICATES FROM t_input COMPARING material budat(6).

  CLEAR p_ergebnis.

  LOOP AT t_input ASSIGNING <l_input>.
    ADD 1 TO buchungen_monate.

    AT END OF material.
      IF buchungen_monate = 12.
        ADD 1 TO p_ergebnis-dauerbrenner.
      ELSEIF buchungen_monate >= 10.
        ADD 1 TO p_ergebnis-saison.
      ELSE.
        ADD 1 TO p_ergebnis-ladenhueter.
      ENDIF.
      CLEAR buchungen_monate.
    ENDAT.
  ENDLOOP.
ENDFORM.                    " vergleich
Viel Spaß beim Tüfteln.
VG Olaf
PS: Ist mal eine nette Abwechslung.

Beitrag von Frank Dittrich (Expert / 674 / 0 / 15 ) »
Ich habe mal Olafs letztes Beispiel als Referenz verwendet (damit die Testläufe nicht ganz so lange dauern) und mit meiner für große Tabellen optimierten Variante verglichen.
Neben dem Vergleich der Summen habe ich noch die jeweils besten Zeiten verglichen,
damit einzelne Ausreißer (s. z.B. die maximale Laufzeit bei 10 Einträgen, verglichen mit der Minimalen für 100) nicht das Ergebnis verfälschen:

Jetzt noch mal überarbeitet - ADD bei Ladenhuetern (und die damit obsoleten WHEN-OTHERS- bzw. ELSE-Anweisungen) weggelassen, und 1 Million Einträge geprüft.

Code: Alles auswählen.

27.05.2004
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:          10  Maximale Materialnummer:             3
Dauerbrenner:                        0
Saisonartikel:                       0
Ladenhueter:                         3
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |         33  ms                        |         32  ms
Maximale Laufzeit:      |         76  ms                        |        172  ms
Mittelwert Laufzeit:    |         43  ms                        |         68  ms
Vergleichsroutine ist um Faktor                     1,03 langsamer als Referenzr
Vergleichsroutine ist um Faktor                     1,59 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:         100  Maximale Materialnummer:             7
Dauerbrenner:                        0
Saisonartikel:                       2
Ladenhueter:                         5
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |        136  ms                        |        132  ms
Maximale Laufzeit:      |        208  ms                        |        264  ms
Mittelwert Laufzeit:    |        151  ms                        |        160  ms
Vergleichsroutine ist um Faktor                     1,03 langsamer als Referenzr
Vergleichsroutine ist um Faktor                     1,06 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:       1.000  Maximale Materialnummer:            35
Dauerbrenner:                       10
Saisonartikel:                      22
Ladenhueter:                         3
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |      1.045  ms                        |      1.059  ms
Maximale Laufzeit:      |      1.105  ms                        |      1.442  ms
Mittelwert Laufzeit:    |      1.061  ms                        |      1.143  ms
Vergleichsroutine ist um Faktor                     1,01 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,08 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:      10.000  Maximale Materialnummer:           252
Dauerbrenner:                      161
Saisonartikel:                      90
Ladenhueter:                         1
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |     11.328  ms                        |     12.517  ms
Maximale Laufzeit:      |     15.673  ms                        |     13.763  ms
Mittelwert Laufzeit:    |     12.475  ms                        |     13.133  ms
Vergleichsroutine ist um Faktor                     1,10 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,05 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:     100.000  Maximale Materialnummer:         2.002
Dauerbrenner:                    1.646
Saisonartikel:                     355
Ladenhueter:                         1
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |    137.600  ms                        |    217.561  ms
Maximale Laufzeit:      |    146.181  ms                        |    268.567  ms
Mittelwert Laufzeit:    |    141.888  ms                        |    229.991  ms
Vergleichsroutine ist um Faktor                     1,58 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,62 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:   1.000.000  Maximale Materialnummer:        16.669
Dauerbrenner:                   15.319
Saisonartikel:                   1.348
Ladenhueter:                         2
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |  2.845.146  ms                        |  3.067.513  ms
Maximale Laufzeit:      |  2.898.925  ms                        |  3.122.678  ms
Mittelwert Laufzeit:    |  2.857.928  ms                        |  3.092.441  ms
Vergleichsroutine ist um Faktor                     1,08 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,08 schneller (Summe)
--------------------------------------------------------------------------------
Gesamtlaufzeit in Mikrosekunden: 68.170.039
Wie man sieht, bricht der Vorsprung meiner Version, der bei 100.000 Einträgen doch recht deutlich ist, bei einer Million Einträgen ganz schön ein.
Ob das mit einer Häufung der beim COLLECT auftretenden Hash-Kollisionen zusammenhängt?
Oder vielleicht eher mit dem READ ... BINARY SEARCH, das zunehmend ineffizienter wird.
Da könnte man noch etwas ändern - wenn auch mit negativem Einfluss auf kleinere itabs.

Mein Code (nach Einbau eines kleinen Hinweises von Stefan):

Code: Alles auswählen.

FORM vergleich USING    t_input     TYPE tyt_input
                        p_max_matnr TYPE i
*                       Uebergabe per Referenz ist schneller,
*                       insbesondere das Kopieren der itab ist Aufwand
*
*                       und in dem Beispiel aendere ich die Parameter
*                       auch nicht, dem Aufrufer kann es also egal sein,
*                       dass ich die Werte nicht per VALUE uebergebe
               CHANGING p_ergebnis  TYPE ty_ergebnis.
*define _rt. " Test-Ausgabe Laufzeit von Einzelschritten
*  format color &1.
*  rt-from = rt-to.
*  get run time field rt-to.
*  rt-step = '&1'.
*  rt-diff = rt-to - rt-from.
*  write: / rt-tfill, rt-max, rt-step, rt-diff.
*end-of-definition.
*
*  statics: begin of rt, max type i, tfill type i, step, from type i, to type i, diff type i, end of rt.
  TYPES ty_char_mat(4) TYPE x.
  DATA: tmp_mat TYPE i VALUE 1. " ty_char_mat VALUE 1.

  DATA: last_tabix TYPE sy-tabix VALUE 1,
        tabix_diff TYPE i,
        my_input TYPE ty_input.
  TYPES: BEGIN OF ty_input2,
           material  TYPE ty_char_mat,
*        vom BUDAT des Originaltyps interessiert mich nur der Monat
           m(2)     TYPE c,
         END OF ty_input2.

  DATA: tmp_wa TYPE ty_input2,
        tmp_input TYPE STANDARD TABLE OF ty_input2
                   WITH NON-UNIQUE KEY material m.

  CLEAR p_ergebnis.
  CHECK NOT t_input IS INITIAL.

* Da SORT in meinem ersten Beispiel am meisten Laufzeit verbrauchte,
* jetzt ein Beispiel, das SORT nur auf eine kleinere Tabelle anwendet
* COLLECT erfordert hier eine Typ-Konvertierung von MATERIAL
*
* Wenn es mehr als 2^22 Kombinationen Material und Monat gibt,
* gibt es beim COLLECT allerdings einen Laufzeitfehler.
* Gibt es mehr als 4 Millionen verschiedene Kombinationen?
  LOOP AT t_input INTO my_input.
    tmp_wa-material = my_input-material.
    tmp_wa-m = my_input-budat+4(2).
    COLLECT tmp_wa INTO tmp_input.
  ENDLOOP.
*  _rt 1.
* Statt SORT Ein weiteres COLLECT in eine neue itab lohnt erst ab
* 10^6 Eintraegen (bzw. mehr als 2002 verschiedenen Materialien)

  SORT tmp_input BY material.
*  _rt 2.

  DO p_max_matnr TIMES.
*   Suche den ersten Index fuer das naechstfolgende Material
    ADD 1 TO tmp_mat.
    READ TABLE tmp_input " INTO tmp_wa
         WITH KEY material = tmp_mat
         BINARY SEARCH TRANSPORTING NO FIELDS.
    CASE sy-subrc.
      WHEN 0.
*       Ermitteln der Anzahl Monate und passenden Zaehler erhoehen
        tabix_diff = sy-tabix - last_tabix.
*       je mehr Eintraege die itab hat, desto wahrscheinlicher sind
*       12 Monate pro Material vorhanden, zumindest im derzeitigen
*       Testszenario (Anzahl verschiedener Materialien / Anzahl Eintraege
*
*       Wenn ich die wahrscheinliche Haeufigkeit der Faelle kenne,
*       kann ich das auch in der Reihenfolge der WHEN-Anweisungen beruecksichtigen
        CASE tabix_diff.
          WHEN 12.
*            ein ADD wegzulassen, war der Tipp von Stefan.
*            Er wollte aber die Anzahl Ladenhueter am Ende berechnen,
*            ich wollte diesen wahrscheinlichsten Fall weglassen und
*            so hoffentlich mehr sparen - hat aber nicht geklappt.

             ADD 1 TO p_ergebnis-dauerbrenner.
          WHEN 11 OR 10.
            ADD 1 TO p_ergebnis-saison.
*          WHEN OTHERS.
*            ADD 1 TO p_ergebnis-ladenhueter.
        ENDCASE.
*      WHEN 4.
**       Materialnummern, die gar nicht vorkommen, werden auch in der Referenzloesung gezaehlt:
*
**       (Da verhaelt Olafs Loesung sich noch anders als die Referenz-Routine.
**       Eine kleine Aenderung korrigiert das - und spart evtl. noch ein wenig Laufzeit.)
 *       ADD 1 TO p_ergebnis-ladenhueter.
      WHEN 8.
*       kein naechstes Material mehr, letzten Eintrag lesen
        READ TABLE tmp_input INTO tmp_wa
             INDEX sy-tfill TRANSPORTING material.
        CASE tmp_wa-material.
          WHEN p_max_matnr.
            tabix_diff = sy-tfill - last_tabix + 1.
            CASE tabix_diff.
              WHEN 12.
                ADD 1 TO p_ergebnis-dauerbrenner.
              WHEN 11 OR 10.
                ADD 1 TO p_ergebnis-saison.
*              WHEN OTHERS.
*                ADD 1 TO p_ergebnis-ladenhueter.
            ENDCASE.
*          WHEN OTHERS.
**           dieses Material und alle weiteren Materialien sind Ladenhueter
*           p_ergebnis-ladenhueter = p_ergebnis-ladenhueter - tmp_wa-material + p_max_matnr.
        ENDCASE.
        EXIT.
    ENDCASE.
*   zuletzt gelesenen Eintrag fuer naechsten Schleifendurchlauf merken
    last_tabix = sy-tabix.
  ENDDO.
*  p_ergebnis-dauerbrenner = p_max_matnr - p_ergebnis-ladenhueter - p_ergebnis-saison.
  p_ergebnis-ladenhueter = p_max_matnr - p_ergebnis-dauerbrenner - p_ergebnis-saison.
*  _rt 3.
*  format color off.
ENDFORM.                    " vergleich
Zuletzt geändert von Frank Dittrich am 27.05.2004 10:50, insgesamt 3-mal geändert.

Beitrag von Frank Dittrich (Expert / 674 / 0 / 15 ) »
Und hier noch der Vergleich meiner ersten Lösung (nach Einbau von Stefans Tipp in meine Lösung und in Olafs Lösung):

Code: Alles auswählen.

27.05.2004
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:          10  Maximale Materialnummer:             3
Dauerbrenner:                        0
Saisonartikel:                       0
Ladenhueter:                         3
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |         27  ms                        |         32  ms
Maximale Laufzeit:      |         64  ms                        |        195  ms
Mittelwert Laufzeit:    |         35  ms                        |         66  ms
Vergleichsroutine ist um Faktor                     1,19 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,86 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:         100  Maximale Materialnummer:             7
Dauerbrenner:                        0
Saisonartikel:                       2
Ladenhueter:                         5
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |         94  ms                        |        136  ms
Maximale Laufzeit:      |        126  ms                        |        267  ms
Mittelwert Laufzeit:    |        101  ms                        |        163  ms
Vergleichsroutine ist um Faktor                     1,45 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,61 schneller (Summe)

--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:       1.000  Maximale Materialnummer:            35
Dauerbrenner:                       10
Saisonartikel:                      22
Ladenhueter:                         3
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |        853  ms                        |      1.075  ms
Maximale Laufzeit:      |        890  ms                        |      1.304  ms
Mittelwert Laufzeit:    |        864  ms                        |      1.167  ms
Vergleichsroutine ist um Faktor                     1,26 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,35 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:      10.000  Maximale Materialnummer:           252
Dauerbrenner:                      161
Saisonartikel:                      90
Ladenhueter:                         1
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |     10.825  ms                        |     12.545  ms
Maximale Laufzeit:      |     12.363  ms                        |     18.124  ms
Mittelwert Laufzeit:    |     11.528  ms                        |     14.022  ms
Vergleichsroutine ist um Faktor                     1,16 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,22 schneller (Summe)
--------------------------------------------------------------------------------
Anz. Eintraege in Tabelle:     100.000  Maximale Materialnummer:         2.002
Dauerbrenner:                    1.646
Saisonartikel:                     355
Ladenhueter:                         1
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |    197.305  ms                        |    224.252  ms
Maximale Laufzeit:      |    203.405  ms                        |    229.539  ms
Mittelwert Laufzeit:    |    199.877  ms                        |    227.151  ms
Vergleichsroutine ist um Faktor                     1,14 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,14 schneller (Summe)
--------------------------------------------------------------------------------
Gesamtlaufzeit in Mikrosekunden:  6.036.417
Hm - aus irgendeinem Grund ist Olafs Lösung durch meine Änderung etwas langsamer geworden. Aber weiter oben stehen ja die Werte für seine Originalversion.

Bei der Geschwindigkeit kann man dann auch mal eine Million Einträge prüfen (hier aber nur mit 3 Wiederholungen):

Code: Alles auswählen.

Anz. Eintraege in Tabelle:   1.000.000  Maximale Materialnummer:        16.669
Dauerbrenner:                   15.319
Saisonartikel:                   1.348
Ladenhueter:                         2
                        | Vergleich                             | Referenz
Minimale Laufzeit:      |  2.842.756  ms                        |  3.053.653  ms
Maximale Laufzeit:      |  2.848.541  ms                        |  3.177.316  ms
Mittelwert Laufzeit:    |  2.846.117  ms                        |  3.121.882  ms
Vergleichsroutine ist um Faktor                     1,07 schneller als Referenzr
Vergleichsroutine ist um Faktor                     1,10 schneller (Summe)
Olafs Lösung kommt meiner immer näher.

Noch eine Anmerkung:
Obwohl (für große Tabellen) viel weniger ADD-Anweisungen weggelassen werden,
ist die Variante, die Ladenhueter am Ende zu berechnen, ein wenig schneller.
(Ich spare mir aber, jetzt den geänderten Quelltext zu posten - das sollte jeder selbst hinkriegen.)

Und mein Quelltext

Code: Alles auswählen.

FORM vergleich USING    t_input     TYPE tyt_input
                        p_max_matnr TYPE i
*                       Uebergabe per Referenz ist schneller,
*                       insbesondere das Kopieren der itab ist Aufwand
*
*                       und in dem Beispiel aendere ich die Parameter
*                       auch nicht, dem Aufrufer kann es also egal sein,
*                       dass ich die Werte nicht per VALUE uebergebe
               CHANGING p_ergebnis  TYPE ty_ergebnis.
*define _rt. " Test-Ausgabe Laufzeit von Einzelschritten
*  format color &1.
*  rt-from = rt-to.
*  get run time field rt-to.
*  rt-step = '&1'.
*  rt-diff = rt-to - rt-from.
*  write: / rt-tfill, rt-max, rt-step, rt-diff.
*end-of-definition.
*
*  statics: begin of rt, max type i, tfill type i, step, from type i, to type i, diff type i, end of rt.
*  TYPES ty_char_mat(4) TYPE x.

  DATA: tmp_mat TYPE i VALUE 1. " ty_char_mat VALUE 1.
  DATA: last_tabix TYPE sy-tabix VALUE 1,
        tabix_diff TYPE i,
        my_input TYPE ty_input.
  TYPES: BEGIN OF ty_input2,
           material  TYPE i,
*        vom BUDAT des Originaltyps interessiert mich nur der Monat
           y(4)     TYPE c,
           m(2)     TYPE c,
           d(2)     TYPE c, " d kann ich auch weglassen
         END OF ty_input2.

  DATA: tmp_wa TYPE ty_input2,
        tmp_input TYPE STANDARD TABLE OF ty_input2
                   WITH NON-UNIQUE KEY material m.

  CLEAR p_ergebnis.
  CHECK NOT t_input IS INITIAL.
  tmp_input = t_input.
*  _rt 1.
  SORT tmp_input BY material m.
*  _rt 2.
  DELETE ADJACENT DUPLICATES FROM tmp_input COMPARING material m.
*  _rt 3.
  DO p_max_matnr TIMES.
*   Suche den ersten Index fuer das naechstfolgende Material
    ADD 1 TO tmp_mat.
    READ TABLE tmp_input " INTO tmp_wa
         WITH KEY material = tmp_mat
         BINARY SEARCH TRANSPORTING NO FIELDS.
    CASE sy-subrc.
      WHEN 0.
*       Ermitteln der Anzahl Monate und passenden Zaehler erhoehen
        tabix_diff = sy-tabix - last_tabix.
*       je mehr Eintraege die itab hat, desto wahrscheinlicher sind
*       12 Monate pro Material vorhanden, zumindest im derzeitigen
*       Testszenario (Anzahl verschiedener Materialien / Anzahl Eintraege
*
*       Wenn ich die wahrscheinliche Haeufigkeit der Faelle kenne,
*       kann ich das auch in der Reihenfolge der WHEN-Anweisungen beruecksichtigen
        CASE tabix_diff.
          WHEN 12.
*            ein ADD wegzulassen, war der Tipp von Stefan.
*            Er wollte aber die Anzahl Ladenhueter am Ende berechnen,
*            ich lasse lieber diesen wahrscheinlichsten Fall weg und
*            spare so hoffentlich mehr

*            ADD 1 TO p_ergebnis-dauerbrenner.
          WHEN 11 OR 10.
            ADD 1 TO p_ergebnis-saison.
          WHEN OTHERS.
            ADD 1 TO p_ergebnis-ladenhueter.
        ENDCASE.
      WHEN 4.
*       Materialnummern, die gar nicht vorkommen, werden auch in der Referenzloesung gezaehlt:
*       (Da verhaelt Olafs Loesung sich noch anders als die Referenz-Routine.
*       Eine kleine Aenderung korrigiert das - und spart evtl. noch ein wenig Laufzeit.)
        ADD 1 TO p_ergebnis-ladenhueter.
      WHEN 8.
*       kein naechstes Material mehr, letzten Eintrag lesen
        READ TABLE tmp_input INTO tmp_wa
             INDEX sy-tfill TRANSPORTING material.
        CASE tmp_wa-material.
          WHEN p_max_matnr.
            tabix_diff = sy-tfill - last_tabix + 1.
            CASE tabix_diff.
              WHEN 12.
*                ADD 1 TO p_ergebnis-dauerbrenner.
              WHEN 11 OR 10.
                ADD 1 TO p_ergebnis-saison.
              WHEN OTHERS.
                ADD 1 TO p_ergebnis-ladenhueter.
            ENDCASE.
          WHEN OTHERS.
*           dieses Material und alle weiteren Materialien sind Ladenhueter
            p_ergebnis-ladenhueter = p_ergebnis-ladenhueter - tmp_wa-material + p_max_matnr.
        ENDCASE.
        EXIT.
    ENDCASE.
*   zuletzt gelesenen Eintrag fuer naechsten Schleifendurchlauf merken
    last_tabix = sy-tabix.
  ENDDO.
  p_ergebnis-dauerbrenner = p_max_matnr - p_ergebnis-ladenhueter - p_ergebnis-saison.
*  _rt 4.
*  format color off.
ENDFORM.                    " vergleich

Beitrag von Hermann ( / / 0 / 3 ) »
Nur mal so der Vollständigkeithalber mein 'Quältext' (bin zum weiteren optimieren bisher noch nicht gekommen):

Code: Alles auswählen.

FORM vergleich USING    value(t_input)     TYPE tyt_input
                        value(p_max_matnr) TYPE i
               CHANGING p_ergebnis         TYPE ty_ergebnis.
* Idee - alle möglichen Werte durchgehen und sehen, wo die auftreten.
  DATA: BEGIN OF monate,
           jan(1) TYPE n,
           feb(1) TYPE n,
           mar(1) TYPE n,
           apr(1) TYPE n,
           mai(1) TYPE n,
           jun(1) TYPE n,
           jul(1) TYPE n,
           aug(1) TYPE n,
           sep(1) TYPE n,
           okt(1) TYPE n,
           nov(1) TYPE n,
           dez(1) TYPE n,
         END OF monate.

  DATA: wa_input         TYPE ty_input,
        testmat          TYPE ty_material,
        buchung(1)       TYPE n,
        buchungen_monate TYPE i,
        my_monat(2)      type n.

*  DATA: tmp_input TYPE SORTED TABLE OF ty_input
*                   WITH NON-UNIQUE KEY material budat.

  data: tmp_input type standard table of ty_input.

  SORT t_input BY material budat+4(2).
  tmp_input = t_input.
  CLEAR p_ergebnis.
  DO p_max_matnr TIMES.

    testmat = sy-index.
    CLEAR: monate, my_monat, buchungen_monate.

    do 12 times.
    my_monat = sy-index.
    read table tmp_input with key material = testmat
                                  budat+4(2) = my_monat
                                  transporting no fields
                                  binary search.

    if sy-subrc eq 0.
     add 1 to buchungen_monate.
    endif.
    enddo.

    IF buchungen_monate = 12.
      ADD 1 TO p_ergebnis-dauerbrenner.
    ELSEIF buchungen_monate >= 10.
      ADD 1 TO p_ergebnis-saison.
    ELSE.
      ADD 1 TO p_ergebnis-ladenhueter.
    ENDIF.

  ENDDO.
ENDFORM.
Hermann

Beitrag von Olaf P. (ForumUser / 61 / 0 / 0 ) »
Hallo Hermann,
Du bist auf dem richtigen Weg. Ich habe Deine Routine nur minimal angepasst und die folgenden Ergebnisse erzielt (Deine geposteten Werte stimmten mit denen auf meinem System überein).

10 1,05 schneller (vorher 1,15 langsamer)
100 2,07 ( vorher 1,65 )
1.000 4,99 ( vorher 3,71 )
10.000 24,73 ( vorher 16,58 )
100.000 232,95 ( vorher 119,26 )

Code: Alles auswählen.

FORM vergleich USING          t_input      TYPE tyt_input
                              p_max_matnr  TYPE i
               CHANGING p_ergebnis         TYPE ty_ergebnis.
* Idee - alle möglichen Werte durchgehen und sehen, wo die auftreten.

  TYPES: BEGIN OF matmm,
           material TYPE ty_material,
           mm(2)    TYPE n,
         END   OF matmm.

  DATA: wa_input         TYPE ty_input,
        testmat          TYPE ty_material,
        buchungen_monate TYPE i,
        my_monat(2)      TYPE n.

  DATA: tmp_input TYPE HASHED TABLE OF matmm WITH UNIQUE KEY material mm,
        l_input   LIKE LINE OF tmp_input.

  LOOP AT t_input INTO wa_input.
    l_input-material = wa_input-material.
    l_input-mm       = wa_input-budat+4(2).
    COLLECT l_input INTO tmp_input.
  ENDLOOP.

  CLEAR p_ergebnis.
  DO p_max_matnr TIMES.
    testmat = sy-index.
    CLEAR buchungen_monate.

    DO 12 TIMES.
      my_monat = sy-index.
      READ TABLE tmp_input WITH TABLE KEY material = testmat
                                          mm       = my_monat
                           TRANSPORTING NO FIELDS.
      IF sy-subrc EQ 0.
        ADD 1 TO buchungen_monate.
      ENDIF.
    ENDDO.

    IF buchungen_monate = 12.
      ADD 1 TO p_ergebnis-dauerbrenner.
    ELSEIF buchungen_monate >= 10.
      ADD 1 TO p_ergebnis-saison.
    ELSE.
      ADD 1 TO p_ergebnis-ladenhueter.
    ENDIF.
  ENDDO.
ENDFORM.                    "vergleich
VG Olaf

Beitrag von Olaf P. (ForumUser / 61 / 0 / 0 ) »
Hallo zusammen,
da nun zu allen bisherigen Ergebnissen auch die Codings vorliegen, will ich Euch das Coding zu meiner zweiten Variante nicht vorenthalten.

Interessant finde ich mal wieder wie viele Wege nach Rom führen.

Code: Alles auswählen.

form vergleich   using          t_input      type tyt_input
                                p_max_matnr  type i
                 changing p_ergebnis         type ty_ergebnis.

  types: begin of ty_mon,
           material  type ty_material,
           monat(6),
         end of ty_mon.

  types: begin of ty_col,
           material type ty_material,
           count type i,
         end of ty_col.

  data: t_mon type hashed table of ty_mon
                    with unique key table_line,
        l_mon like line of t_mon.

  data: t_col type hashed table of ty_col
                    with unique key material,
        l_col like line of t_col.

  l_col-count = 1.
  loop at t_input into l_mon.
    insert l_mon into table t_mon.
    check sy-subrc = 0.
    l_col-material = l_mon-material.
    collect l_col into t_col.
  endloop.

  clear p_ergebnis.

  loop at t_col into l_col.
    if l_col-count = 12.
      add 1 to p_ergebnis-dauerbrenner.
    elseif l_col-count >= 10.
      add 1 to p_ergebnis-saison.
    else.
      add 1 to p_ergebnis-ladenhueter.
    endif.
  endloop.
endform.                    " vergleich
VG Olaf

Vergleichbare Themen

0
Antw.
1385
Views
[Linktip]Tuning des SAP BW & EasyBW
von M. Lahr » 25.03.2006 09:42 • Verfasst in Sonstige Module
5
Antw.
2455
Views
Laufzeitoptimierung
von ABAP_DEV » 27.07.2020 14:50 • Verfasst in ABAP® Core
1
Antw.
1470
Views
Tabellen durchscannnen - Laufzeitoptimierung Z_SCAN_TABLE
von jspranz » 17.03.2006 14:39 • Verfasst in ABAP® Core

Newsletter Anmeldung

Keine Beiträge verpassen! Wöchentlich versenden wir lesenwerte Beiträge aus unserer Community.
Die letzte Ausgabe findest du hier.
Details zum Versandverfahren und zu Ihren Widerrufsmöglichkeiten findest du in unserer Datenschutzerklärung.