Code: Alles auswählen.
SELECT t~feld1 t~feld2 t~feld3 t~feld4
FROM Tiban AS t
INNER JOIN lfa1 AS k
ON t~tabkey = k~lifnr
INTO TABLE itab1
FOR ALL ENTRIES IN itabtr
Where k~erdat => itabtr-erdat
AND t~iban = itabtr-iban.
uff... ich kenne die Tabelle Tiban nicht, aber das würde ich, im allgemeinen, nicht raten. Das wird performance mäßig nichts bringen, insbesondere wenn die Anzahl der Einträge groß ist. Ich würde, wie A6272 schon geschrieben hat, die Indizes mal überprüfen und dann noch schauen ob man bei der WHERE Bedingung nicht noch mehr eingrenzen kann..A6272 hat geschrieben:oder alles ertmal laden und dann per FILTER das unerwünsche entfernen.
Heißt also, immer davor ein if zu setzen:Wenn die Tabelle, zu der andere Einträge gelesen werden sollen, leer ist, dann werden alle Einträge der anderen Tabelle gelesen!!!
Code: Alles auswählen.
if lines( itab ) > 0.
select .... for all entries ... .
endif.
Weiß garnicht ob das hier erlaubt istL0w-RiDer hat geschrieben:Hallo,
ich wollte mir hier mal ein paar Meinungen und Ratschläge einholen und zwar habe ich folgendes Problem. Ich selektiere aus einer Datenbanktabelle bestimmte Werte mit Einschränkungen auf einer anderen Tabelle (Treibertabelle) per For All Entries. Nun ist das alles sehr langsam, deshalb wollte ich mal fragen was es für Möglichkeiten geben würde den Code umzustellen oder andere Optionen im Vergleich zum For all Entries um das Ganze performanter zu gestalten.
Vielen Dank.
Dies wäre der Code: ( Ich hab es aus Datenschutzgründen etwas abgeändert, aber der Sinn ist der gleiche)
...
Code: Alles auswählen.
SELECT FELD1 FELD2 FELD3 FELD4
FROM TIBAN AS T
INTO TABLE ITAB1
FOR ALL ENTRIES IN ITABTR
WHERE IBAN = ITABTR-IBAN
AND EXISTS ( SELECT * FROM LFA1
WHERE LIFNR = TIBAN~TABKEY
AND ERDAT >= ITABTR-ERDAT ).
Das ist in der Tat egal: der Optimizer stellt sich das so hin wie er es braucht.DeathAndPain hat geschrieben: Was mir zunächst mal auffällt, ist die seitenverdrehte Prüfung in ON-Statement. Statt ON t~tabkey = k~lifnr müsste es ON k~lifnr = t~tabkey lauten, denn im ON-Statement soll ja der Zugriff auf k (a.k.a. lfa1) eingeschränkt werden, und da schreibt man das zu prüfende Feld links und den Prüfwert rechts. Ich staune, dass das so syntaktisch überhaupt akzeptiert wird. Es kann natürlich sein, dass der ABAP-Compiler die Ungenauigkeit erkennt und im Hintergrund ausgleicht. Genauso gut aber könnte ich mir vorstellen, dass dies dazu führt, dass auf der lfa1 der Index nicht mehr genutzt wird.
Ja, das ist hier trivial gegeben. Die lfa1 hat als einziges Primärschlüsselfeld LIFNR, und die TIBAN hat einen expliziten Index auf dem Feld IBAN. Der SELECT ist einfach genug, dass kein Datenbankoptimizer ein Problem haben sollte, damit einen korrekten Indexzugriff hinzubekommen.Zugriffspfad
Sind Felder der WHERE-Klauseln in Indizes, die benutzt werden können?
Wir reden von der Tabelle lfa1 der Lieferanten. Wieviele Lieferanten soll die Firma des Threaderstellers haben? Da wäre vierstellig schon viel. Das sind keine problematischen Größenordnungen.Datenmenge
Wie groß ist die Treibertabelle?
Anders herum gesprochen ist es nur noch ein Fünftel der Zugriffe verglichen mit dem klassischen Ansatz, die EInträge per SELECT SINGLE einzeln durchzugehen.Da hier tatsächlich eine Aufteilung stattfindet (wie schon geschrieben 5er-Blöcke o.ä.) vervielfacht sich die Anzahl der DB-Zugriffe. Wenn also 100 Einträge in der Treibertabelle sind werden daraus (im Beispiel) 20 DB-Zugriffe.
Das macht SAP bei FOR ALL ENTRIES IN automatisch.- itab doppelte Einträge entfernen, weiß nicht ob SAP oder die DB das implizit macht
Performancemäßig wird das keine Vorteile bringen. Das muss ja auch in SQL für die Datenbak übersetzt werden; da kann er ja nicht mehr machen, als doch wieder die Werte einzeln aufzuzählen.- vermutlich ist es langsamer aber wenn es nicht zu viele Einträge sind (da gibt es Grenzen) als Ranges-Tabelle WHERE ... IN ... ist vlt. einen Versuch wert
Jein.DeathAndPain hat geschrieben:Das macht SAP bei FOR ALL ENTRIES IN automatisch.- itab doppelte Einträge entfernen, weiß nicht ob SAP oder die DB das implizit macht
ABAP Hilfe hat geschrieben: * Bezüglich doppelt vorkommender Zeilen in der Ergebnismenge wirkt der Zusatz FOR ALL ENTRIES so, als sei der Zusatz DISTINCT in der Definition der Selektionsmenge angegeben. Im Unterschied zu DISTINCT werden die Zeilen aber nicht immer vom Datenbanksystem sondern unter Umständen erst auf dem Applikationsserver aus der Ergebnismenge entfernt. Die doppelten Zeilen werden dann vom Datenbanksystem entfernt, wenn die SELECT-Anweisung als eine einzige SQL-Anweisung an das Datenbanksystem übergeben werden kann. Falls die SELECT-Anweisung auf mehrere SQL-Anweisungen verteilt übergeben werden muss, findet die Verdichtung auf dem Applikationsserver statt.
* Wenn doppelte Zeilen erst auf dem Applikationsserver entfernt werden, werden in manchen Konstellationen alle durch die WHERE-Bedingung spezifizierten Zeilen an eine interne Systemtabelle übergeben und in dieser verdichtet. Die maximale Größe dieser Systemtabelle ist wie die normaler interner Tabellen beschränkt. Insbesondere wird die Systemtabelle immer benötigt, wenn gleichzeitig einer der Zusätze PACKAGE SIZE oder UP TO n ROWS verwendet wird. Diese wirken dann nicht auf die Menge der vom Datenbankserver an den Applikationsserver übergebenen Zeilen, sondern werden erst für die Übergabe der Zeilen von der Systemtabelle an den eigentlichen Zielbereich verwendet. Wenn die maximale Größe der internen Systemtabelle überschritten wird, kommt es zu einem Laufzeitfehler.
Doch, performancemäßig bringt das einiges, weil die Werte an die Datenbank in viel größeren Paketen übergeben werden können. Z.b. unter Oracle, wo die Übergabe bei FOR ALL ENTRIES ja standardmäßig mit nur 5 eingestellt ist.DeathAndPain hat geschrieben:Performancemäßig wird das keine Vorteile bringen. Das muss ja auch in SQL für die Datenbak übersetzt werden; da kann er ja nicht mehr machen, als doch wieder die Werte einzeln aufzuzählen.- vermutlich ist es langsamer aber wenn es nicht zu viele Einträge sind (da gibt es Grenzen) als Ranges-Tabelle WHERE ... IN ... ist vlt. einen Versuch wert
Das ist ein guter Rat, weil so die gesamte Logik in der DB liegt und deren Optimizer dann den günstigsten Zugriffspfad wählen kann.DeathAndPain hat geschrieben:Da würde ich eher zu der zuvor von mir genannten Subquery raten. Dann ist es wirklich nur eine einzige Anfrage, und alles andere passiert im Inneren der Datenbank (da Subquerys sich direkt in Native SQL übersetzen lassen).
Nicht "defaultmäßig", sondern das ist die von der SAP empfohlene Einstellung für Oracle. Der Grund für diese Empfehlung (bzw. generell dafür, weshalb es da überhaupt einen Grenzwert gibt) wird irgendwo in den SAP-Hinweisen auch erwähnt: Ab einer gewissen Menge übergebener Einzelwerte entscheidet sich die Optimierer der Datenbank nicht mehr dafür, den Index zu verwenden, sondern rast sequenziell durch die Tabelle, um auf diese Weise alle angefragten Einzelwerte abzugrasen. Offenbar ist dies jedoch deutlich ineffizienter, als für jeden Einzelwert den Index zu nutzen, weswegen es besser ist, die FOR ALL ENTRIES-Anfrage in so viele Teilanfragen aufzuteilen, dass der Optimierer jede einzelne, mit dem IN-Operator übertragene Teilanfrage noch über den Index abwickelt. Mit anderen Worten: SAP hat Gründe, weshalb sie das so empfehlen.Doch, performancemäßig bringt das einiges, weil die Werte an die Datenbank in viel größeren Paketen übergeben werden können. Z.b. unter Oracle, wo die Übergabe bei FOR ALL ENTRIES ja standardmäßig mit nur 5 eingestellt ist.
Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag:
a-dead-trousers
Niceblack_adept hat geschrieben:Ab irgend einem Release hat SAP die "global temporary tables" eingeführt. Eventuell könnte man die statt des FOR ALL ENTRIES verwenden.