Monat: Januar 2015

Rätsel der verlorenen Session

Das Heutige Rätsel ist herausfordernder als die früheren. Ich gebe auch zu,dass es vielleicht auch noch eine andere Lösung geben könnte, als die, die wir in der Realität gefunden haben.
Es will mir allerdings keine einfallen.
Aber lest selbst:
In der Datenbank eines Kunden tauchten in regelmässigen Abständen immer wieder unangenehme row cache lock waits auf. Der row cache lock war von Type 7, das ist dc_users. Ich erzeugte einen System State Dump, wie z.B. hier beschrieben: System State Dumps.
Es war eine ganze Reihe von blockierten und blockierenden Sessions im dump.
Wenn ich die blockiere Session im Dump finden wollte um heraus zu finden welches Statement geschickt wird, konnte ich die Session nicht finden.
Es gelang mir, in real time die SIDs von blockierenden Sessions zu ermitteln. Aber die Session selbst war nie da.
Welches Statement setzten die blockierenden Sessions ab?

Advertisements

Lösung: Eine Funktion in der Where Bedingung

Selbstverständlich hat Martin Berger wieder einmal recht:

    1. Die Funktion ist überflüssig und sollte entfernt werden
    2. Die Funktion ist nicht als deterministisch definiert, obwohl sie maximal deterministisch ist. Als Konsequenz kann man keinen Funktion based Index anlegen, keine virtuelle Spalte und auch keine Extended Statistics erzeugen.
    3. natürlich wäre es sinnvoll den result cache zu nutzen. In der Funktionsdefinition fehlt dieses Schlüsselwort.
    4. Als letzte flächendeckende Massnahme könnte man der Funktion Statistiken zu ordnen. Dies wird hier Table Expressions, Cardinality, SYS_OP_ATG and KOKBF und hier setting cardinality for pipelined and table functions beschrieben. Leider ist dies nicht möglich, weil ein Fehler in der where Bedingung eine implizite Konversion erzwingt. Aus effective  wird to_number (effective..) . Statistiken die mit der original Funktion effective verknüpft sind, werden dadurch unwirksam

Damit hat der Entwickler mittels beindruckender Inkompetenz alle Möglichkeiten für eine elegante Lösung vernichtet und wir müssen das Statement über hints festlegen. Dies gelang über einen sql patch.

Eine Funktion in der Where Bedingung

Hier die Definition der Funktion:
FUNCTION effective (p_id IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
-- IF   p_id  = '0'
--    OR p_id = current_id
--    OR current_id = '0'
-- THEN
RETURN('1');
-- ELSE
--   RETURN('0');
-- END IF;
END;

Diese Funktion wird wie folgt verwendet:
Where effective(id) = 1 ...

Was kann man an diesen beiden Textfragmenten besser machen?  Zeigen Sie alle Nöglichkeiten auf.

 

 

Lösung: Die verlorene Zeit

Die Antwort lautet Netzwerklatenz.

Vielen Dank an meine Kommentatoren, die natürlich total richtig liegen. Da die SQL Befehle schnell genug sind, muss das Problem an anderer Stelle liegen. Das vermeintliche idle wait event Sql*net Message from client hätte im trace auffallen sollen.

Ein Blick ins trace Resultat bestätigte die Vermutung. Von Craig Shallahammer hatte ich gelernt, dass man die Latenzzeit im Netzwerk mit einem einfachen Ping testen kann. Unsere Versuche zeigten schnell, dass man die Abweichung in the Laufzeiten ziemlich gut mit Anzahl Datenbankaufrufe * Zeit pro Ping * 2 berechnen konnte.

Daraus habe ich geschlossen, dass pro Datenbankaufruf zwei Netzwerktransfers stattfinden. Ich vermute dass der zweite ein Aknowledge ist, habe das aber nie überprüft.

Um das Problem kurzfristig zu lösen musste man als die Netzwerklatenz verkürzen. Zur damaligen Zeit war technisch nur Citrix als Lösung möglich. Langfristig war es erforderlich (um die Citrix Lizenz ein zu sparen) die Anzahl der Datenbankaufrufe zu reduzieren, in dem an mehrere Befehle zusammen fasst. (Wie man es von Anfang an hätte tun sollen.)