2. Ich sage, dass die Tabellen gepuffert werdenDeathAndPain hat geschrieben:nickname8, Du solltest Deine Überzeugungen unbedingt sorgsamer mit der Realität abgleichen, bevor Du sie im Brustton der Überzeugung vorträgst. Was Du hier alles an zweifelhaften Behauptungen aufgestellt hast, geht auf keine Kuhhaut. Damit verunsicherst Du andere Anwender und schickst sie auf falsche Gleise.
Ich habe auch mal geglaubt, dass hashed-Tabellen besser seien. Bis ich mir irgendwann mal die Mühe gemacht habe, ein Testprogramm zu schreiben und die Performance zu messen. (Irgendwo hier gibt es noch den Thread, in dem ich das Programm und meine Messergebnisse vorgestellt habe.) Das Ergebnis war, dass das Füllen der Hashtabelle (wohl wegen der Berechnung der Hashes) um so viel langsamer war, dass man hinterher Abertausende von Suchvorgängen brauchen würde, damit sich dieser Nachteil gegenüber einer sorted table amortisiert. Dabei nützt es auch nichts, von besonders großen Tabellen auszugehen. Bei denen ist der (geringe) Suchvorteil der hashed table zwar größer, dafür sind aber auch entsprechend mehr Hashes beim Befüllen der Tabelle zu berechnen.nickname8 hat geschrieben:- sortierte oder noch besser hashed tabellen nutzen
3. Ich sage, dass die REGUP eine Clustertabelle istDeathAndPain hat geschrieben:Die ABAP-Tabellenpufferung hat damit gar nichts zu tun, die ist nämlich nur bei Tabellen überschaubarer Größe (typischerweise Customizingtabellen) aktiviert, nicht bei den Anwendungsdatentabellen, auf die man in seinen Programmen meist zugreift. Der hier beschriebene Effekt tritt jedoch auch bei letzteren auf. Ursache ist, dass die Datenbanken selber auch puffern. Wer oft hintereinander auf dieselbe Tabelle oder gar dieselben Sätze der Tabelle zugreift, bekommt die späteren Zugriffe wesentlich schneller erledigt. Das ist nicht so schnell wie die ABAP-Tabellenpufferung, die SAP-serverseitig im Hauptspeicher erfolgt und schon gar nicht so schnell wie eine durchdacht programmierte Pufferung in einer sortierten internen Tabelle, aber es ist allemal drastisch schneller als ein erstmaliger Zugriff.nickname8 hat geschrieben:Wird es.Tommy hat geschrieben:anscheinend wird das irgendwie gepuffert...
https://ibb.co/HGR3XmF
Zu 1.:DeathAndPain hat geschrieben:Auf was für einem alten Release sitzt Du? Die SAP stellt Clustertabellen nach und nach auf transparente Tabellen um, und auf meinem 7.50 ist die REGUP auch eine transparente Tabelle. Weitere Indizes sind trotzdem nicht darauf definiert, aber das könnte man notfalls selber machen. Sollte man natürlich möglichst vermeiden, weil es bei großen Tabelle viel Speicherplatz und auch etwas Rechenzeit kostet.nickname8 hat geschrieben:- REGUP ist eine Clustertabelle - da gibts keine zusätzlichen Indizes drauf
Code: Alles auswählen.
INITIALIZATION.
PARAMETERS: p_rows TYPE i.
START-OF-SELECTION.
TYPES:
BEGIN OF t_key,
tabname TYPE dd03l-tabname,
fieldname TYPE dd03l-fieldname,
as4local TYPE dd03l-as4local,
as4vers TYPE dd03l-as4vers,
position TYPE dd03l-position,
END OF t_key.
DATA lt_dd03l_hashed TYPE HASHED TABLE OF dd03l WITH UNIQUE KEY tabname fieldname as4local as4vers position.
DATA lt_dd03l_sorted TYPE SORTED TABLE OF dd03l WITH NON-UNIQUE KEY tabname fieldname as4local as4vers position.
DATA ls_dd03l TYPE dd03l.
DATA lv_int TYPE i.
DATA lt_key TYPE TABLE OF t_key.
DATA ls_key TYPE t_key.
SELECT * UP TO @p_rows ROWS
FROM dd03l
INTO TABLE @DATA(lt_dd03l).
DATA(lv_lines) = lines( lt_dd03l ).
lv_int = sy-timlo.
DATA(lo_ran) = cl_abap_random_int=>create( min = 1 max = lv_lines seed = lv_int ).
DO lv_lines TIMES.
CLEAR ls_key.
lv_int = lo_ran->get_next( ).
READ TABLE lt_dd03l INTO ls_dd03l INDEX lv_int.
ls_key-tabname = ls_dd03l-tabname.
ls_key-fieldname = ls_dd03l-fieldname.
ls_key-as4local = ls_dd03l-as4local.
ls_key-as4vers = ls_dd03l-as4vers.
ls_key-position = ls_dd03l-position.
APPEND ls_key TO lt_key.
ENDDO.
GET RUN TIME FIELD DATA(m0).
lt_dd03l_hashed = lt_dd03l.
GET RUN TIME FIELD DATA(m1).
LOOP AT lt_key ASSIGNING FIELD-SYMBOL(<fs>).
READ TABLE lt_dd03l_hashed WITH TABLE KEY tabname = <fs>-tabname
fieldname = <fs>-fieldname
as4local = <fs>-as4local
as4vers = <fs>-as4vers
position = <fs>-position
TRANSPORTING NO FIELDS.
ENDLOOP.
GET RUN TIME FIELD DATA(m2).
DATA(e0) = m1 - m0.
DATA(e1) = m2 - m1.
DATA(e5) = m2 - m0.
WRITE: 'Befüllen HASHED TABLE: ', e0.
WRITE: / 'READ HASHED TABLE: ', e1.
WRITE: / 'Gesamt HASHED TABLE: ', e5.
WRITE /.
GET RUN TIME FIELD DATA(m3).
lt_dd03l_sorted = lt_dd03l.
GET RUN TIME FIELD DATA(m4).
LOOP AT lt_key ASSIGNING <fs>.
READ TABLE lt_dd03l_sorted WITH TABLE KEY tabname = <fs>-tabname
fieldname = <fs>-fieldname
as4local = <fs>-as4local
as4vers = <fs>-as4vers
position = <fs>-position
TRANSPORTING NO FIELDS.
ENDLOOP.
GET RUN TIME FIELD DATA(m5).
DATA(e2) = m4 - m3.
DATA(e3) = m5 - m4.
DATA(e4) = m5 - m3.
WRITE: 'Befüllen SORTED TABLE: ', e2.
WRITE: / 'READ SORTED TABLE: ', e3.
WRITE: / 'Gesamt SORTED TABLE: ', e4.
Alt. Zu alt.DeathAndPain hat geschrieben: Auf was für einem alten Release sitzt Du?
Wer weiß auf welchem Release Bright4.5 sitzt...DeathAndPain hat geschrieben:Die SAP stellt Clustertabellen nach und nach auf transparente Tabellen um, und auf meinem 7.50 ist die REGUP auch eine transparente Tabelle. Weitere Indizes sind trotzdem nicht darauf definiert, aber das könnte man notfalls selber machen. Sollte man natürlich möglichst vermeiden, weil es bei großen Tabelle viel Speicherplatz und auch etwas Rechenzeit kostet.
Das wird ja immer als Argument verwendet um für Hash-Tabellen zu werben. Allerdings ist D&Ps Vergleich nicht von der Hand zu weisen.nickname8 hat geschrieben:Zu 1.:
Wusste gar nicht, dass O(1) langsamer ist als O(log(n)) .
Code: Alles auswählen.
report.
parameters: p_rows type i default 100000.
parameters: p_doread type i default 5.
data: itkey type standard table of t100.
data: ithash type hashed table of t100 with unique key sprsl arbgb msgnr.
data: itsort type sorted table of t100 with unique key sprsl arbgb msgnr.
data: rtm_start type timestampl.
data: rtm_stop type timestampl.
data: rtm_diff type timestampl.
select * into table itkey from t100 up to p_rows rows.
"hash
get time stamp field rtm_start.
loop at itkey assigning field-symbol(<wakey>).
insert <wakey> into table ithash.
endloop.
get time stamp field rtm_stop.
compute rtm_diff = rtm_stop - rtm_start.
write: /01 rtm_diff, 'hash build rtm'.
rtm_start = rtm_stop.
do p_doread times.
loop at itkey assigning <wakey>.
read table ithash
assigning field-symbol(<wahash>)
with key sprsl = <wakey>-sprsl
arbgb = <wakey>-arbgb
msgnr = <wakey>-msgnr.
endloop.
enddo.
get time stamp field rtm_stop.
rtm_diff = rtm_stop - rtm_start.
write: /01 rtm_diff, 'hash read rtm'. uline.
"sorted
get time stamp field rtm_start.
loop at itkey assigning <wakey>.
insert <wakey> into table itsort.
endloop.
get time stamp field rtm_stop.
rtm_diff = rtm_stop - rtm_start.
write: /01 rtm_diff, 'sorted build rtm'.
rtm_start = rtm_stop.
do p_doread times.
loop at itkey assigning <wakey>.
read table itsort
assigning field-symbol(<wasorted>)
with key sprsl = <wakey>-sprsl
arbgb = <wakey>-arbgb
msgnr = <wakey>-msgnr.
endloop.
enddo.
get time stamp field rtm_stop.
compute rtm_diff = rtm_stop - rtm_start.
write: /01 rtm_diff, 'sorted read rtm'.
Womit wir wieder beim Thema "Theorie und Praxis" wären. Zum einen habe ich messen können, dass zumindest in der ABAP-Implementierung O(1) nicht hinhaut, denn bei sehr vielen Tabelleneinträgen maß ich auch bei Verwendung einer Hashtabelle eine längere Suchzeit als bei wenigen. Zum anderen hast Du aber den (schon von black_adept angeführten) Knackpunkt ignoriert, der zentraler Kernpunkt meiner Argumentation war: dass nämlich Hashtabellen (wie alle anderen auch) erst gefüllt werden müssen, bevor man sie benutzen kann. Und, um mich inhaltlich zu wiederholen: Dass Befüllen einer Hashtabelle dauert aufgrund der Notwendigkeit, für jede einzelne Zeile einen Hashwert zu berechnen, so viel länger als das Befüllen einer sortierten Tabelle, dass Du hinterher Abertausende von Suchvorgängen bräuchtest, um durch den geringen Suchzeitvorteil von Hashtabellen die ganze Zeit auszugleichen, die Du vorher beim Befüllen der Hashtabelle zusätzlich verbrannt hast! Nach meiner Praxiserfahrung kommt es so gut wie nie vor, dass man so oft in einer internen Tabelle suchen muss, dass man hier den Amortisationspunkt erreichen würde. Außer vielleicht wenn man schlampig programmiert und dieselbe Suche immer wiederholt, anstatt mit dem einmal gefundenen Ergebnis weiterzuarbeiten.nickname8 hat geschrieben:Zu 1.:
Wusste gar nicht, dass O(1) langsamer ist als O(log(n)) .
Nein. Du hast die T002 überhaupt nicht erwähnt, sondern nur auf einen Screenshot von ihr verlinkt. Und dazu hast Du gesagt, dass die Daten, um die es hier im Thread gehen würde, die nicht aus der T002 stammen und die mit hoher Wahrscheinlichkeit aus einer nicht im ABAP gepufferten Tabelle stammen, auf diese Weise gepuffert werden würden:nickname8 hat geschrieben:Zu 2.:
ich sagte, dass die Tabelle T002 vollständig gepuffert ist.
Immerhin bedeutet es, dass man die Chance hat, sich selber einen Index draufzulegen, wenn man für seine Kundenanwendungen einen benötigt. Ist formal gesehen zwar eine Modifikation, aber eine der harmlosesten Sorte (auch wenn nicht völlig auszuschließen ist, dass innerhalb des SAP-Standardcodes der Datenbankoptimierer eine schlechte Wahl trifft und den kundeneigenen Index wählt, obgleich an der Stelle der Standardindex besser wäre, so dass im Standard die Performance plötzlich schlechter wäre. Dazu müsste man aber das ganz große Los ziehen; das ist extrem unwahrscheinlich. Besonders dann, wenn man sich bei der Auswahl jenes Indexes Gedanken macht, statt da inkompetent wahllos irgendwelche Felder reinzuschreiben).nickname8 hat geschrieben:Wer weiß auf welchem Release Bright4.5 sitzt...
Ändert aber nichts an der Tatsache, dass keine Indizes drauf sind. Egal ob Cluster oder Transparent.
Damit quälst Du Dich selber aber ohne Not doppelt: Du hast die schlechtere Gesamtperformance und zudem den verringerten Programmierkomfort, weil Du die Option, mit Tabellenindex auf die Tabelle zuzugreifen, herschenkst. Wenn man das nicht braucht und im Gegenzug bessere Performance dafür kriegen würde, würde ich einen Sinn darin sehen, so aber ist es ein loss/loss-Szenario.black_adept hat geschrieben:( P.S. Auch wenn ich hier D&Ps Argumentation nachvollziehen kann - ich persönlich verwende fast immer Hashtabellen wo es mir sinnvoll erscheint wobei ich mich dann immer wieder über mich selbst ärgere, wenn ich einen Loop über eine Hash-Tabelle mache um dann den Fehler machen den sy-tabix abzufragen )
Wenn Du von S/4 HANA redest: Das gibt es für HCM leider noch nicht (kommt aber). Insofern kann ich dazu noch keine Aussage machen. Ich habe mich nur auf interne Tabellen bezogen, vermute aber, dass es für diese auch in S/4 gelten wird, da diese so oder so im Hauptspeicher liegen.black_adept hat geschrieben:@D&P:
ad 2) Tabellenpufferung: Gilt dies Aussage bzgl. nicht gepufferter Anwendungstabellen auch für In-Memory-Computing?
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
Legxis
Ich habe die T002 nicht erwähnt, aber Tommy Nightmare hat es gemacht. In seinem Beispielcoding. Sorry, ich war so naiv zu glauben, dass man sich den kompletten Thread durchliest und nicht nur einzelne Beiträge. Ich denke, dass der Kontext schon wichtig ist...DeathAndPain hat geschrieben: Nein. Du hast die T002 überhaupt nicht erwähnt, sondern nur auf einen Screenshot von ihr verlinkt. Und dazu hast Du gesagt, dass die Daten, um die es hier im Thread gehen würde, die nicht aus der T002 stammen und die mit hoher Wahrscheinlichkeit aus einer nicht im ABAP gepufferten Tabelle stammen, auf diese Weise gepuffert werden würden:
Hast du dafür auch ein Beispielcoding? Wie du meinem Beispielcoding entnehmen kannst, habe ich einen Gegenbeispiel mit dem Erstellen der HASH-Tabelle geliefert.DeathAndPain hat geschrieben:Womit wir wieder beim Thema "Theorie und Praxis" wären. Zum einen habe ich messen können, dass zumindest in der ABAP-Implementierung O(1) nicht hinhaut, denn bei sehr vielen Tabelleneinträgen maß ich auch bei Verwendung einer Hashtabelle eine längere Suchzeit als bei wenigen. Zum anderen hast Du aber den (schon von black_adept angeführten) Knackpunkt ignoriert, der zentraler Kernpunkt meiner Argumentation war: dass nämlich Hashtabellen (wie alle anderen auch) erst gefüllt werden müssen, bevor man sie benutzen kann. Und, um mich inhaltlich zu wiederholen: Dass Befüllen einer Hashtabelle dauert aufgrund der Notwendigkeit, für jede einzelne Zeile einen Hashwert zu berechnen, so viel länger als das Befüllen einer sortierten Tabelle, dass Du hinterher Abertausende von Suchvorgängen bräuchtest, um durch den geringen Suchzeitvorteil von Hashtabellen die ganze Zeit auszugleichen, die Du vorher beim Befüllen der Hashtabelle zusätzlich verbrannt hast! Nach meiner Praxiserfahrung kommt es so gut wie nie vor, dass man so oft in einer internen Tabelle suchen muss, dass man hier den Amortisationspunkt erreichen würde. Außer vielleicht wenn man schlampig programmiert und dieselbe Suche immer wiederholt, anstatt mit dem einmal gefundenen Ergebnis weiterzuarbeiten.nickname8 hat geschrieben:Zu 1.:
Wusste gar nicht, dass O(1) langsamer ist als O(log(n)) .
Code: Alles auswählen.
*&---------------------------------------------------------------------*
*& Report ZTEST_TABLE_SEARCH
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZTEST_TABLE_SEARCH.
DATA: T_STANDARD TYPE STANDARD TABLE OF PERSNO WITH HEADER LINE,
T_SORTED TYPE SORTED TABLE OF PERSNO WITH UNIQUE DEFAULT KEY WITH HEADER LINE,
T_HASHED TYPE HASHED TABLE OF PERSNO WITH UNIQUE DEFAULT KEY WITH HEADER LINE,
I TYPE I,
J TYPE I,
RUNTIME TYPE I.
PARAMETERS: ENTRIES TYPE I OBLIGATORY.
*** START-OF-SELECTION ***
START-OF-SELECTION.
* Fill standard table
GET RUN TIME FIELD I.
DO ENTRIES TIMES.
T_STANDARD = SY-INDEX.
INSERT TABLE T_STANDARD.
ENDDO.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Fill Standard table:', RUNTIME.
* Fill sorted table
GET RUN TIME FIELD I.
DO ENTRIES TIMES.
T_SORTED = SY-INDEX.
INSERT TABLE T_SORTED.
ENDDO.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Fill Sorted table:', RUNTIME.
* Fill hashed table
GET RUN TIME FIELD I.
DO ENTRIES TIMES.
T_HASHED = SY-INDEX.
INSERT TABLE T_HASHED.
ENDDO.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Fill Hashed table:', RUNTIME.
* Search standard table
GET RUN TIME FIELD I.
READ TABLE T_STANDARD WITH KEY TABLE_LINE = T_STANDARD.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Search last entry of Standard table:', RUNTIME.
* Search sorted table
GET RUN TIME FIELD I.
READ TABLE T_SORTED WITH KEY TABLE_LINE = T_STANDARD.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Search last entry of Sorted table:', RUNTIME.
* Search hashed table
GET RUN TIME FIELD I.
READ TABLE T_HASHED WITH KEY TABLE_LINE = T_STANDARD.
GET RUN TIME FIELD J.
RUNTIME = J - I.
WRITE: / 'Search last entry of Hashed table:', RUNTIME.
SKIP.
WRITE 'Results are in micro seconds.'.
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
tm987456
Haben über 50 Systeme bei uns. Ich bin meistens auf den alten System unterwegs mit ABAP 7.02.DeathAndPain hat geschrieben:@nickname8: In Deinem Testprogramm schmeißt Du mit Inline-Datendeklarationen um Dich. Und da behauptest Du, auf einem alten Release zu sitzen?