Voldoende maar niet-excessief loggen

Voldoende, maar niet excessief

Bij het registreren van logging is de noodzakelijk om een balans te raken tussen voldoende en niet teveel logging. Vaak begint een programma met een eenvoudig logica om een paar gegevens te verwerken, maar groeit het onderweg uit naar het verwerken van miljoenen financiële transacties.

In dit artikel leer je hoe je eenvoudig voldoende, maar niet excessief kunt loggen in een loop.

SQL

Meestal gebeurt het loggen in Invantive PSQL met een constructie zoals:

begin
  for r in ( QUERY )
  loop
    -- Do something with r.
    dbms_output.put_line('I have processed a row.');
  end loop;
end;

Als de query een miljoen regels oplevert, dan zullen er na verwerking ook een miljoen regels in de logging staan. Echter, de gemiddelde toegevoegde analytische waarde van een extra logmelding is normaliter kleiner dan de vorige toegevoegde regel. Het is handig om gaandeweg steeds minder vaak een melding af te drukken. Een eerste aanzet is:

begin
  for r in ( QUERY )
  loop
    -- Do something with r.
    if teller < 10
    then
      dbms_output.put_line('I have processed a row.');
  end if;
  end loop;
end;

Deze benadering heeft als nadeel dat je eigenlijk steeds minder vaak een melding wil, maar wel nog steeds af en toe. Dat kan af en toe zijn in termen van tijd of in termen van aantallen verwerkte rijen.

De volgende query laat een methode zien om met telkens langere tussenpozen een logmelding te genereren:

select value
,      mod(value, power(3, floor(log(value, 3)))) = 0
       print_status
       label 'Print Status?'
from   RANGE@DataDictionary(10000,1)

Logging minder vaak

In de afbeelding is te zien dat de eerste 3 candidaten altijd afgedrukt worden, daarna 1 per 3 en daarna 1 per 9. Dit gaat zover: 1 per 27, 1 per 81, etc…

Door te spelen met de constanten kan een ander snelheid van afname gekozen worden. Gebruik je bijvoorbeeld 10 in plaats van 3, dan krijg je een terugkoppeling bij de rijen 1…10, 20, 30, …, 100, 200, etc.

In een stukje PSQL ziet dat als volgt uit:

begin
  for r in ( QUERY )
  loop
    -- Do something with r.
    if mod(teller, power(3, floor(log(teller, 3)))) = 0
    then
      dbms_output.put_line('I have processed a row.');
  end if;
  end loop;
end;

Op deze wijze wordt ook bij een groot aantal verwerkte gegevens het aantal logmeldingen niet excessief; het aantal groeit logaritmisch in plaats van lineair.

Prestaties

Logging veroorzaakt altijd enige overhead. Een log en power (machtsverheffen) zijn niet altijd efficient. Mocht het gaan om extreem grote volumes, dan kan het verstandig zijn om een macht van 2 te gebruiken, zodat de rekentijd beperkt wordt door optimalisaties in log en power.