SELECT + LOOP: Geschwindigkeit?

Getting started ... Alles für einen gelungenen Start.
36 Beiträge Seite 1 von 3 (current) Nächste
36 Beiträge Seite 1 von 3 (current) Nächste

SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 15. Nov 2019 13:25

Hallo alle!

Ich habe auch ein schräges Phänomen (ähnlich dem Thema mit "schräg" im Titel):

Mein Programm ist folgendermaßen aufgebaut:

- mords-SELECT über Vertriebsbelege, das initial schon einmal viel liest, in eine interne Tabelle

-großes loop über diese interne Tabelle, die diese mit weiteren Daten anreichert, u.a.
--SELECT auf die Partner einer Auftragspos (und -kopf, weil es oft keine Pos.partner gibt) in eine interne Tabelle, dann ein loop darüber, das verschiedene Partnerdaten ausliest.

SAT hat ausgegeben, dass SELECT VBPA eine der "teuersten" Anweisungen ist. Also dachte ich, ich mache zwischen initialem select und dem großen loop ein SELECT FROM VBPA FOR ALL ENTRIES, also ich lese auf einen Schwung alle Partnerdaten aller vorher gefundenen Verkaufsbelege, erspare mir damit dieses SELECT pro Zeile im großen LOOP, und mach das LOOP über die Partner dann mit der WHERE-Bedingung des bisherigen SELECTs.

SAT wirft entsprechend aus, dass SELECT VBPA jetzt viel weniger Zeit beansprucht, aber das Programm läuft jetzt fast doppelt so lang! Nämlich dieses große loop braucht viel länger! (was durch an der eingebauten Fortschrittsanzeige beobachtbar ist)
Und in SAT ist nicht zu sehen, welche Anweisung hier genau länger braucht- da kommt kein neuer hoher Wert vor (oder ich bin zu doof...).

Kann es sein, dass diese LOOP-WHERE-Konstruktion so langsam ist? Ist ja das einzige, das hier "komplexer" geworden ist.

Vielen Dank im Voraus für die Hilfe!

lg, Wolfgang


Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von black_adept (Top Expert / 3316 / 60 / 605 ) » 15. Nov 2019 13:31

foxtrot hat geschrieben:
15. Nov 2019 13:25
Kann es sein, dass diese LOOP-WHERE-Konstruktion so langsam ist? Ist ja das einzige, das hier "komplexer" geworden ist.
Wenn es eine sortierte Tabelle ist und WHERE ein Anfangsstück des Schlüssels ist: Nein
Sonst: Ja
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 15. Nov 2019 13:49

An sich ist die Tabelle von vornherein passend sortiert, aber ich habe inzwischen auch noch ausprobiert, noch einmal bewusst so zu sortieren: kein bisschen schneller.

Hab in SAT nun auch gefunden, wo ich LOOPs mitprotokollieren kann - ja, dieses loop sticht heraus, aber das beschreibt ja nur das ganze loop mit "Inhalt", und nicht, ob es das loop selbst ist...

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von DeathAndPain (Top Expert / 1184 / 132 / 256 ) » 15. Nov 2019 15:03

Also zum einen wäre es an dieser Stelle extrem hilfreich, wenn Du den betreffenden Code selbst posten könntest, anstatt nur darüber zu schreiben. Wer weiß, was da drinsteht, was Dir nicht aufgefallen ist und was wir nicht erkennen können, wenn wir es nicht zu sehen bekommen.

Zum anderen hängt die Performance von FOR ALL ENTRIES IN sehr davon ab, dass die Systemparameter richtig (d.h. passend zu und abhängig von der verwendeten Datenbank) eingestellt sind. Da gibt es von der SAP Hinweise mit Empfehlungen zu. Ich geb mal aus der Erinnerung wieder (im Zweifel aber den richtigen Hinweis raussuchen): Der Parameter sollte so stehen, dass FOR ALL ENTRIES IN in ein IN-Statement umgewandelt wird. Bei Oracle sollte der Parameter so stehen, dass für je 5 Zeilen ein neuer SELECT gemacht wird. Bei Sybase reicht ein neuer SELECT alle 128 Zeilen.

Und bitte nicht vergessen, Deinen Code zu posten (vorzugsweise unter Nutzung des CODE-Tags).

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von ewx (Top Expert / 4088 / 179 / 403 ) » 15. Nov 2019 15:47

foxtrot hat geschrieben:
15. Nov 2019 13:49
An sich ist die Tabelle von vornherein passend sortiert
Das bedeutet nicht zwingend, dass du eine Tabelle vom Typ SORTED TABLE hast!
Das bedeutet nicht zwingend, dass deine STANDARD Tabelle einen passend definierten Schlüssel hat!

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von DeathAndPain (Top Expert / 1184 / 132 / 256 ) » 15. Nov 2019 16:03

All das und womöglich noch mehr würden wir erfahren, wenn wir den Code zu Gesicht bekämen. Vorzugsweise einschließlich sämtlicher Typ- und Datendeklarationen.

Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
SaskuAc (18. Nov 2019 08:11)


Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 18. Nov 2019 08:27

DeathAndPain hat geschrieben:
15. Nov 2019 15:03
Also zum einen wäre es an dieser Stelle extrem hilfreich, wenn Du den betreffenden Code selbst posten könntest, anstatt nur darüber zu schreiben. Wer weiß, was da drinsteht, was Dir nicht aufgefallen ist und was wir nicht erkennen können, wenn wir es nicht zu sehen bekommen.
Nachdem mein Problem offenbar nicht so ganz einfach zu lösen ist, wird das wohl nötig.
Zum anderen hängt die Performance von FOR ALL ENTRIES IN sehr davon ab, ...
Dieses select macht keine Geschwindigkeitsprobleme.
ewx hat geschrieben:
15. Nov 2019 15:47
Das bedeutet nicht zwingend, dass du eine Tabelle vom Typ SORTED TABLE hast!
Das bedeutet nicht zwingend, dass deine STANDARD Tabelle einen passend definierten Schlüssel hat!
Ich hab jetzt einmal eine sorted table draus gemacht, hat nichts gebracht.

Also hier der betreffende Programmtext:

Code: Alles auswählen.

  DATA: lw_vbpa    TYPE vbpa,
        lt_vbpa    TYPE SORTED TABLE OF vbpa
                     WITH UNIQUE KEY vbeln posnr parvw,

*...

* hier kommt ein initiales select, das hier nur unnötig sperrig wäre; 
* Ergebnis: lt_select_tab

*...

 * dieses select geht schnell:
    SELECT * FROM vbpa INTO TABLE lt_vbpa
     FOR ALL ENTRIES IN lt_select_tab
     WHERE vbeln = lt_select_tab-vbeln.

  LOOP AT lt_select_tab INTO lw_select_tab.
*...
    MOVE-CORRESPONDING lw_select_tab TO lw_grid_tab.
*...

*frühere Version, wo das loop schneller war:
*    CLEAR lt_vbpa.
*    SELECT * FROM vbpa INTO TABLE lt_vbpa
*      WHERE vbeln = lw_grid_tab-vbeln
*      AND   ( posnr = 0 OR posnr = lw_grid_tab-posnr ).

* jetzt mit obigem select vbap:
    LOOP AT lt_vbpa INTO lw_vbpa
      WHERE vbeln = lw_grid_tab-vbeln
      AND   ( posnr = 0 OR posnr = lw_grid_tab-posnr ).
      CASE lw_vbpa-parvw.
*...
Und genau das LOOP AT lt_vbpa steht in SAT an erster Stelle in der Hitliste...

Ah ja, das LOOP AT lt_vbpa hatte in der schnelleren Version natürlich keine WHERE-Bedingung.
Zuletzt geändert von foxtrot am 18. Nov 2019 08:29, insgesamt 1-mal geändert.

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von M@atze! (ForumUser / 72 / 6 / 11 ) » 18. Nov 2019 08:29

Hi,

wie bereits angefragt wäre dein Code hierzu schon sehr hilfreich.

Ich wage mal einen Schuss ins Blaue:

Wenn du einen "großen" Loop über die Ergebnisse eines "mords"-Select`s laufen lässt arbeitest du dann mit INTO?
Wenn ja, probier es mal mit einem Feldsymbol und ASSIGNING.

Das sollte die Durchlaufzeit deines Loops beschleunigen.

Gruß
Matze

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von JHM (Top Expert / 1138 / 0 / 179 ) » 18. Nov 2019 09:28

foxtrot hat geschrieben:
18. Nov 2019 08:27
Ah ja, das LOOP AT lt_vbpa hatte in der schnelleren Version natürlich keine WHERE-Bedingung.
Evtl. hilft dir dieser Link: https://blogs.sap.com/2007/09/12/runtim ... al-tables/
Dort wird das "Laufzeitverhalten" bei nested loops erklärt.

Das OR in der WHERE-Bedingung ist mMn nicht gerade förderlich, find aber gerade keinen Beleg. Evtl. wären zwei bedingte READ TABLE je Partnerart performanter.

Du ließt im allgemeinen sehr viele Daten (SELECT *), verwendest du alle?
Benötigst du wirklich alle PARVW aus der VBPA?
Datensparsamkeit kommt der Laufzeit immer zu Gute. Zumal du mit Arbeitsbereichen anstatt Field-Symbols bei den LOOPs arbeitest. Es müssen sehr viele Daten "kopiert" werden in deinem Loop.
Gruß Hendrik

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 18. Nov 2019 10:09

JHM hat geschrieben:
18. Nov 2019 09:28
Evtl. hilft dir dieser Link: https://blogs.sap.com/2007/09/12/runtim ... al-tables/
Dort wird das "Laufzeitverhalten" bei nested loops erklärt.
Danke, war an sich interessant, aber hat jetzt keine großartigen Auswirkungen - es wird empfohlen, eine sorted table zu verwenden, was ich mittlerweile tue und jetzt auch nicht wirklich was gebracht hat.
Das OR in der WHERE-Bedingung ist mMn nicht gerade förderlich, find aber gerade keinen Beleg. Evtl. wären zwei bedingte READ TABLE je Partnerart performanter.
Das Problem ist, dass es Positionspartner geben kann oder auch nicht - das OR kann ich nur mit
READ WHERE posnr = posnr
IF sy-subrc NE 0
READ WHERE posnr = 0
umgehen. Und das für jede Partnerrolle, die ich lese, das sind (derzeit) vier. Ob das effizienter ist?
Du ließt im allgemeinen sehr viele Daten (SELECT *), verwendest du alle?
Die VBPA ist nicht sehr "breit", und wie gesagt, das (derzeitige) SELECT auf vbpa ist eh schnell - würde eine "schmälere" interne Tabelle wesentlich schneller sein? Ich würde es jetzt einmal nicht erwarten.
Benötigst du wirklich alle PARVW aus der VBPA?
Datensparsamkeit kommt der Laufzeit immer zu Gute.
Grob die Hälfte der Partner brauche ich aktuell. Das kann ich einmal probieren... tatsächlich, das hat das Programm schneller gemacht als in der ersten Version!
Gegenprobe: das select im loop (auskommentierte "erste" Version) ist fast genauso schnell...

Das war jetzt eine schöne Beschleunigung, aber eigentlich würde mich interessieren, wieso mein Hauptspeicher-loop so lahm ist, dass ich in der Zeit auch 10.000 selects machen kann...
Zumal du mit Arbeitsbereichen anstatt Field-Symbols bei den LOOPs arbeitest. Es müssen sehr viele Daten "kopiert" werden in deinem Loop.
field symbols muss ich mir erst anschauen - wir sind hier immerhin im Anfänger-Berech ;)
Aber danke für die Anregungen!

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 18. Nov 2019 10:29

...Korrektur: die Version mit dem select außerhalb vom loop mit eingeschränkten Partnerrollen ist doch nicht schneller, da hab ich mich beim Stoppen vertan (ich hab nur auf die Uhr geschaut, weil ein anderer Test lief...). Knapp langsamer als "Version 1".

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von DeathAndPain (Top Expert / 1184 / 132 / 256 ) » 18. Nov 2019 12:36

Das mit den FIELD-SYMBOLS sollte man generell machen, aber es bringt nicht viel und taugt nicht wirklich als Erklärung. Die würde ich schon eher in dem OR sehen. Dadurch, dass Du so eine komplexe Bedingung für die Positionsnummer angibst, kann das System den Index Deiner internen Tabelle auf dieselbe nicht nutzen. Indizes lassen sich nur nutzen, wenn auf Gleichheit geprüft wird (beim letzten Kriterium auch auf größer/kleiner).

Nach meiner Überzeugung wärst Du schneller, wenn Du folgendes machen würdest (hier gleich in der Fassung mit Feldsymbol; ginge äquivalent aber auch ohne):

Code: Alles auswählen.

LOOP AT lt_vbpa ASSIGNING FIELD-SYMBOL(<lw_vbpa>) WHERE vbeln = lw_grid_tab-vbeln
                                                    AND posnr = '000000'.
  PERFORM whatever_you_wanna_do USING <lw_vbpa>.
ENDLOOP.

LOOP AT lt_vbpa ASSIGNING <lw_vbpa> WHERE vbeln = lw_grid_tab-vbeln
                                      AND posnr = lw_grid_tab-posnr.
  PERFORM whatever_you_wanna_do USING <lw_vbpa>.
ENDLOOP.
Dann nutzt jeder Zugriff auf die lt_vbpa den vollen Index VBLEN/POSNR, den Du bei der Definition Deiner internen Tabelle angegeben hast. Ansonsten hast Du beim LOOP halt eine sequentielle Suche durch alle Positionen Deiner internen Tabelle. Ich staune zwar, dass Deine Vertriebsbelege so viele Positionen haben, dass das einen nennenswerten Unterschied macht, aber mit obenstehendem Code hättest Du es optimal (Voraussetzung für diese Syntax: mindestens Release 7.40).

Das Feldsymbol darfst Du übrigens bei obenstehendem Code vorher nicht deklarieren, das passiert inline direkt bei dem LOOP.

Der zweite Punkt ist der, dass Du mit dem Vergleich POSNR = 0 ein NUMC mit einem INT vergleichst. Das kann ABAP zwar, aber auch dadurch geht im LOOP die Indexnutzung den Bach runter. Schreib daher korrekt den Initialwert von POSNR, also '000000'.

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 18. Nov 2019 12:58

DeathAndPain hat geschrieben:
18. Nov 2019 12:36
Das mit den FIELD-SYMBOLS sollte man generell machen, aber es bringt nicht viel und taugt nicht wirklich als Erklärung. Die würde ich schon eher in dem OR sehen. Dadurch, dass Du so eine komplexe Bedingung für die Positionsnummer angibst, kann das System den Index Deiner internen Tabelle auf dieselbe nicht nutzen. Indizes lassen sich nur nutzen, wenn auf Gleichheit geprüft wird (beim letzten Kriterium auch auf größer/kleiner).
naja, auf Gleichheit prüfe ich ja, nur mit OR... aber wenn das das Problem ist...
Nach meiner Überzeugung wärst Du schneller, wenn Du folgendes machen würdest (hier gleich in der Fassung mit Feldsymbol; ginge äquivalent aber auch ohne):

Code: Alles auswählen.

LOOP AT lt_vbpa ASSIGNING FIELD-SYMBOL(<lw_vbpa>) WHERE vbeln = lw_grid_tab-vbeln
                                                    AND posnr = '000000'.
  PERFORM whatever_you_wanna_do USING <lw_vbpa>.
ENDLOOP.

LOOP AT lt_vbpa ASSIGNING <lw_vbpa> WHERE vbeln = lw_grid_tab-vbeln
                                      AND posnr = lw_grid_tab-posnr.
  PERFORM whatever_you_wanna_do USING <lw_vbpa>.
ENDLOOP.
Dann nutzt jeder Zugriff auf die lt_vbpa den vollen Index VBLEN/POSNR, den Du bei der Definition Deiner internen Tabelle angegeben hast.
Nicht den vollen, denn parvw gehört auch noch dazu, und damit kommts dann meiner READ-Struktur gleich.
(ich steh pro Zeile des äußeren loops auf der Pos, und ich muss zuerst schauen, ob es einen Pos-Partner gibt, sonst auf den Kopf-Partner zurückgreifen)
Ich staune zwar, dass Deine Vertriebsbelege so viele Positionen haben, dass das einen nennenswerten Unterschied macht,
Es ist noch komplexer: Vertriebsbelege haben manchmal viele, manchmal wenige Positionen, und Positionspartner gibts wiederum gar nicht so oft, aber wenn es sie gibt, muss ich sie nehmen.
Der zweite Punkt ist der, dass Du mit dem Vergleich POSNR = 0 ein NUMC mit einem INT vergleichst. Das kann ABAP zwar, aber auch dadurch geht im LOOP die Indexnutzung den Bach runter. Schreib daher korrekt den Initialwert von POSNR, also '000000'.
Das hätte ich jetzt beinahe überlesen...
ausprobiert - exakt gleich schnell (so genau mein Daumen bei 21s stoppen kann), auch mit IS INITIAL.

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von DeathAndPain (Top Expert / 1184 / 132 / 256 ) » 18. Nov 2019 13:48

naja, auf Gleichheit prüfe ich ja, nur mit OR... aber wenn das das Problem ist...
Logisch ja, aber syntaktisch erzeugst Du mit Deinem OR eine Komplexität, die der ABAP-Interpreter hinsichtlich der Indexnutzung nicht mehr auflösen kann. Der will einfach die einzelnen Indexelemente mit AND verknüpft in der Reihenfolge sehen, wie sie auch in Deiner Tabellendeklaration stehen.
Nicht den vollen, denn parvw gehört auch noch dazu
Das habe ich gesehen, aber den schränkst Du ja nicht ein, willst also alle Sätze davon haben. Andernfalls würde ein LOOP ja auch keinen Sinn machen, denn wenn Du den vollständigen Schlüssel einer mit UNIQUE KEY deklarierten Tabelle angeben würdest, könntest Du maximal ein Ergebnis erhalten und wärst daher mit READ TABLE oder der moderneren Release 4.70-Syntax davon besser aufgestellt.

Der LOOP wertet die eingegebenen Spalten von links nach rechts aus und nutzt dabei den Tabellenschlüssel, solange Deine WHERE-Bedingung diesen einhält. Wolltest Du noch andere Spalten einschränken, die nicht Teil des Schlüssels sind, solltest Du diese Bedingungen ans Ende Deiner WHERE-Klausel stellen.

Vom Grundsatz her ist das bei WHERE-Bedingungen von Datenbank-SELECTs übrigens nicht anders, nur dass diese von einem mit Eigenintelligenz ausgestatteten Optimierer ausgewertet werden. Details wie Bedingungen, die nicht in der Reihenfolge des Tabellenindex angegeben werden, biegt dieser eigenständig gerade, aber bei einem geklammerten OR wie in Deinem Fall würde ich auch bei einem Datenbank-SELECT erwarten, dass die Indexnutzung nicht klappt. (Dafür kannst Du bei Datenbank-SELECTS auf den IN-Operator zurückgreifen.)
(ich steh pro Zeile des äußeren loops auf der Pos, und ich muss zuerst schauen, ob es einen Pos-Partner gibt, sonst auf den Kopf-Partner zurückgreifen)
Wenn das durch die Prüfung auf POSNR IS INITIAL repräsentiert wird, dann könntest Du da auch nochmal optimieren und meinen Codevorschlag wie folgt umstellen:

Code: Alles auswählen.

LOOP AT lt_vbpa ASSIGNING FIELD-SYMBOL(<lw_vbpa>) WHERE vbeln = lw_grid_tab-vbeln
                                                    AND posnr = lw_grid_tab-posnr.
  PERFORM whatever_you_wanna_do USING <lw_vbpa>.
ENDLOOP.

IF sy-subrc <> 0.
  LOOP AT lt_vbpa ASSIGNING <lw_vbpa> WHERE vbeln = lw_grid_tab-vbeln
                                        AND posnr = '000000'.
    PERFORM whatever_you_wanna_do USING <lw_vbpa>.
  ENDLOOP.
ENDIF.
Dann würdest Du Dir das Lesen des Kopfpartners sparen, wenn Du Positionspartner findest und hättest damit nochmals Performance rausgemolken.

Hast Du meinen Code denn mal ausprobiert und die Performance durchgemessen?
so genau mein Daumen bei 21s stoppen kann
Du weißt aber, dass es ABAP-Befehle zur Laufzeitmessung gibt? Lies Dir mal die F1-Hilfe von GET RUN TIME durch.

Re: SELECT + LOOP: Geschwindigkeit?

Beitrag von foxtrot (ForumUser / 28 / 1 / 0 ) » 18. Nov 2019 13:52

so, jetzt hab ich das mal so gemacht:

Code: Alles auswählen.

    READ TABLE lt_vbpa
      WITH KEY vbeln = lw_grid_tab-vbeln
               posnr = lw_grid_tab-posnr
               parvw = 'AG'
      INTO lw_vbpa.
    IF sy-subrc NE 0.
      READ TABLE lt_vbpa
        WITH KEY vbeln = lw_grid_tab-vbeln
                 posnr = '000000'
                 parvw = 'AG'
        INTO lw_vbpa.
    ENDIF.


und das für jede Partnerrolle;
jaaa, immer noch nicht mit field symbols, damit ich nicht alles umbauen muss... aber wenn das eh nicht viel bringt...
(und ja, table key wäre noch sauberer, aber binär wird hier auch gesucht, laut help)

So bin ich bei meinen Testdaten auf 13s herunten - mit den vielen selects auf die vier gesuchten Partnerrollen war ich auf 12s...
Schön ist anders...

Die Idee mit den beiden loops, einmal mit 000000, einmal mit posnr, habe ich jetzt erst voll verstanden, nämlich dass das prinzipiell soweit gehen würde (Positionspartner überschreiben Kopfpartner, wenn vorhanden), nur kommt noch was dazu: es gibt auch select options auf Partner. Wenn Kopf- und Pos-Partner verschieden sind und einer der Partner nicht in der Selektion ist, wirds "interessant"...

Wenn es bei dieser Anforderung so schwierig ist, das einmalige select auf die vbpa dann effizient zu verwerten, und letztlich bin ich nicht schneller als "Version 1" mit eingeschränkten Partnerrollen, tendiere ich zu letzterer Version - es bleibt übersichtlicher.

Oder hat wer noch eine Idee?

lg, Wolfgang

Seite 1 von 3 (current) Nächste

Aktuelle Forenbeiträge

PopUp bei Fakturaerstellung
vor 3 Minuten von jocoder 2 / 16
Generische Objekte in der Massenverarbeitung
vor 43 Minuten von TravellingEntwickler 2 / 583
Unterschiedliche Konditionen AB und Rechnungdruck
vor 6 Stunden von Sebastian82 1 / 34
Anzahlungsrechnung drucken
vor 7 Stunden von Sebastian82 1 / 30

Unbeantwortete Forenbeiträge

Unterschiedliche Konditionen AB und Rechnungdruck
vor 6 Stunden von Sebastian82 1 / 34
Anzahlungsrechnung drucken
vor 7 Stunden von Sebastian82 1 / 30
Änderungsbelege für Kundenfelder im BP
vor 4 Tagen von GerryRe 1 / 1990
Transaktionen MEIS / VE01
vor einer Woche von SAP_ENTWICKLER 1 / 2462