Code: Alles auswählen.
*&---------------------------------------------------------------------*
*& Report ZTEST_TABLE_SEARCH
*&---------------------------------------------------------------------*
REPORT ZTEST_TABLE_SEARCH2.
DATA: T_OBJID TYPE STANDARD TABLE OF HROBJID WITH HEADER LINE,
I TYPE I,
J TYPE I,
RUNTIME TYPE I.
PARAMETERS: JN_FIRST RADIOBUTTON GROUP ONE,
SB_FIRST RADIOBUTTON GROUP ONE,
EX_FIRST RADIOBUTTON GROUP ONE.
*** START-OF-SELECTION ***
START-OF-SELECTION.
CASE 'X'.
WHEN JN_FIRST.
PERFORM SELECT_WITH_JOIN.
WRITE: / 'Join:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_SUBQUERY.
WRITE: / 'Subquery:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_EXISTS.
WRITE: / 'Exists-Clause:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
WHEN SB_FIRST.
PERFORM SELECT_WITH_SUBQUERY.
WRITE: / 'Subquery:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_JOIN.
WRITE: / 'Join:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_EXISTS.
WRITE: / 'Exists-Clause:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
WHEN EX_FIRST.
PERFORM SELECT_WITH_EXISTS.
WRITE: / 'Exists-Clause:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_SUBQUERY.
WRITE: / 'Subquery:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
PERFORM SELECT_WITH_JOIN.
WRITE: / 'Join:', RUNTIME, 'microseconds'.
WRITE: / LINES( T_OBJID ), 'table entries'.
ENDCASE.
*&---------------------------------------------------------------------*
*& Form SELECT_WITH_JOIN
*&---------------------------------------------------------------------*
FORM SELECT_WITH_JOIN.
GET RUN TIME FIELD I.
SELECT OBJID INTO TABLE T_OBJID FROM PA0001
JOIN HRP1001 ON HRP1001~SOBID = PA0001~PERNR
WHERE PA0001~WERKS = 'Z001'
AND PA0001~BEGDA <= SY-DATUM
AND PA0001~ENDDA >= SY-DATUM.
GET RUN TIME FIELD J.
RUNTIME = J - I.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form SELECT_WITH_SUBQUERY
*&---------------------------------------------------------------------*
FORM SELECT_WITH_SUBQUERY.
GET RUN TIME FIELD I.
SELECT OBJID INTO TABLE T_OBJID FROM HRP1001
WHERE SOBID IN ( SELECT PERNR FROM PA0001
WHERE WERKS = 'Z001'
AND PA0001~BEGDA <= SY-DATUM
AND PA0001~ENDDA >= SY-DATUM ).
GET RUN TIME FIELD J.
RUNTIME = J - I.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form SELECT_WITH_EXISTS
*&---------------------------------------------------------------------*
FORM SELECT_WITH_EXISTS.
GET RUN TIME FIELD I.
SELECT OBJID INTO TABLE T_OBJID FROM HRP1001
WHERE EXISTS ( SELECT PERNR FROM PA0001
WHERE PERNR = HRP1001~SOBID
AND WERKS = 'Z001'
AND PA0001~BEGDA <= SY-DATUM
AND PA0001~ENDDA >= SY-DATUM ).
GET RUN TIME FIELD J.
RUNTIME = J - I.
ENDFORM.
"BYPASSING BUFFER" bezieht sich meines Wissens nur auf die SAP-seitige Pufferung, die in der SE11 im Bereich "Technische Einstellungen" der Tabelle definiert ist. Große Tabellen (wie die hier von mir verwendeten) haben hier normalerweise "Pufferung nicht erlaubt" zu stehen, was bedeutet, dass die SAP-Pufferung für sie sowieso nicht aktiv ist.Kannst du mit "BYPASSING BUFFER" nicht den Cache überlisten um eine bessere Messgenauigkeit zu erzielen
Mein Beispiel ist ja relativ willkürlch gewählt, und auf dem Entwicklungssystem haben wir auch nicht mal annähernd so viel Daten. Ich wollte den Report aber als lokales Objekt ohne Transport machen, so dass ich ihn in den Folgesystemen nicht ausprobieren kann. Außerdem ist das ja nur ein einziger SELECT. Den fühlt man selten. In produktiven Programmen läppert sich das aber, je nachdem, ob man immer eine effiziente oder immer eine ineffiziente Codingweise verwendet. Auch wenn es hier nicht viel ausmacht: wenn Du alle Deine Datenbankzugriffe 5% schneller machen könntest, nur durch eine andere Art und Weise, Dein Statement zu schreiben (aber auf eine vergleichbar gut lesbare Art und Weise), würdest Du das nicht gerne als kleinen, aber kostenlosen Bonus mitnehmen? Deswegen würde ich das halt gerne einmal klären, welcher Ansatz der performanteste ist und mir den dann (ohne Nachteile) angewöhnen. Nur laufe ich halt in das Problem der nicht allzu vollen Datenbank im Entwicklungssystem und des Datenbank-Cachings.Wenn die Laufzeit nur "gefühlt" unterschiedlich ist und du mehrere Anläufe unternehmen musst um evtl. einen Unterschied zu bemerken - ist es dann nicht egal welche der Varianten du verwendest?
Schau Dir die SELECTs an (in den drei kleinen Formroutinen ganz am Ende des Programms). Ist da einer bedeutend besser oder schlechter lesbar als der andere?Wenn alle Laufzeiten im grünen Bereich sind: Nimm den lesbarsten
Im Prinzip richtig, aber wenn Du Dir meine SELECTs anschaust, dann wirst Du sehen, dass da im Prinzip dieselben Indizes genutzt werden, nur auf verschiedene Art und Weise. Natürlich kann es immer umständeabhängige Effekte geben. Es kann sogar sein, dass unter Oracle das eine Statement schneller ist und unter Sybase das andere. Ich wollte halt etwas Brainstorming haben, was man noch alles zur Entscheidungsfindung heranziehen könnte. Vielleicht fällt ja dem einen oder anderen zu den gewählten Ansätzen meiner drei SELECT-Statements was Ergänzendes ein.Aber egal, was bei diesem speziellen Vergleich herauskommt, wirst du nicht pauschal sagen können: Variante X ist immer schneller, da es wahrscheinlich immer auf verschiedene Umstände ankommt:
Rate mal, was ich gemacht habe. Oben im Ausgangsposting findest Du es, bereit für Copy & Paste in Dein Entwicklungssystem!Es ist deswegen immer ratsam im Zweifel ein kleines Testprogramm zu schreiben.
Ich meinte auch nicht deine drei SELECTS im Speziellen sondern irgendwelche anderen SELECTS mit anderen Tabellen.DeathAndPain hat geschrieben:Im Prinzip richtig, aber wenn Du Dir meine SELECTs anschaust, dann wirst Du sehen, dass da im Prinzip dieselben Indizes genutzt werden, nur auf verschiedene Art und Weise. Natürlich kann es immer umständeabhängige Effekte geben. Es kann sogar sein, dass unter Oracle das eine Statement schneller ist und unter Sybase das andere.Aber egal, was bei diesem speziellen Vergleich herauskommt, wirst du nicht pauschal sagen können: Variante X ist immer schneller, da es wahrscheinlich immer auf verschiedene Umstände ankommt:
FOR ALL ENTRIES könnte man vielleicht noch prüfen. Das sind zwar dann zwei Selects aber das muss nicht schlechter sein.DeathAndPain hat geschrieben:Ich wollte halt etwas Brainstorming haben, was man noch alles zur Entscheidungsfindung heranziehen könnte. Vielleicht fällt ja dem einen oder anderen zu den gewählten Ansätzen meiner drei SELECT-Statements was Ergänzendes ein.
Ich habe dein Posting gelesen, bevor ich geantwortet habe...!DeathAndPain hat geschrieben:Rate mal, was ich gemacht habe. Oben im Ausgangsposting findest Du es, bereit für Copy & Paste in Dein Entwicklungssystem!Es ist deswegen immer ratsam im Zweifel ein kleines Testprogramm zu schreiben.
Das wäre aber mehr als überraschend, wenn das performanter wäre. Zum einen liest Du damit eine Staffel Werte in den Hauptspeicher, die Du dort gar nicht brauchst, um sie anschließend an die Datenbank zurückzugeben, zum anderen ist bekannt, dass ABAP den FOR ALL ENTRIES in IN (..., ..., ...)-Klauseln umsetzt, bevor es sie an die Datenbank schickt. Dabei gibt es eine Obergrenze an Werten in dem IN-Statement, bevor ein neuer SELECT angefangen wird. Diese Obergrenze sitzt in einem Profilparameter und soll verhindern, dass der Datenbankoptimierer sich angesichts der vielen Einzelwerte für einen sequenziellen Zugriff entscheidet (der trotzdem deutlich schlechter wäre). Defaultmäßig beträgt dieser Wert bei Oracle nach meiner Erinnerung 5, bei Sybase immerhin 128. Das bedeutet, dass die Datenbank bei dieser Variante nicht nur die beiden von Dir angesprochenen SELECTs bekommt, sondern alle 5 bzw. 128 Tabelleneinträge einen weiteren. Das kann nie und nimmer so effizient sein, wie der Datenbank einen einzigen SELECT zu übergeben, der alle Informationen enthält, und sie dann eigenständig unter Nutzung ihrer eingebauten Optimierungsalgorithmen machen zu lassen.FOR ALL ENTRIES könnte man vielleicht noch prüfen. Das sind zwar dann zwei Selects aber das muss nicht schlechter sein.
Wenn ich so etwas mit ordentlichen Daten im Q-System überprüfen will, packe ich das in ein LSMW-Projekt. Das ist dann ganz fix getestet.DeathAndPain hat geschrieben:Mein Beispiel ist ja relativ willkürlch gewählt, und auf dem Entwicklungssystem haben wir auch nicht mal annähernd so viel Daten. Ich wollte den Report aber als lokales Objekt ohne Transport machen, so dass ich ihn in den Folgesystemen nicht ausprobieren kann.
15 Minuten. Länger dauert es nicht, Dein Programm in ein LSMW-Projekt zu packen und im Testsystem(Q) laufen zu lassen.DeathAndPain hat geschrieben:Mal abgesehen davon, dass die LSMW auch Grenzen hat: Das Verschieben von Daten zwischen Systemen ist hier nicht der Engpass, dafür gibt es im HCM das verbreitete Tool Clone&Test von Accenture. Die Sache ist aber die, dass produktive Daten nicht in ein Entwicklungssystem gehören. Auch nicht anonymisiert zum Testen; dafür ist das Testsystem da.