Nach einem kürzlichen Upgrade auf 12.1.0.2 habe ich an einer Reihe von Leistungsproblemen gearbeitet. Viele dieser Probleme hängen mit schlechtem SQL zusammen, und eine Reihe von Problemen, die ich gelöst habe, waren nachweislich Probleme in der alten Version 11.2.0.4. Das bedeutet nur, dass es immer ein Problem war. Aber die Leute nutzen die Gelegenheit des Upgrades, um mich dazu zu bringen, Dinge zu reparieren, die seit geraumer Zeit kaputt sind.
Bei der Betrachtung von Leistungsproblemen bin ich auf zwei SQL-Anweisungen gestoßen, die in unserem System zu Schweinen werden. Hier ist ein Screenshot der beiden SQL-Anweisungen, wie sie in Lighty zu sehen sind:
Wir können sehen, dass die erste SQL-Anweisung (SQL-ID 4b4wp0a8dvkf0) CPU verbraucht und auf Lesevorgänge aus der Steuerdatei wartet. Die zweite SQL-Anweisung (SQL-ID frjd8zfy2jfdq) verwendet viel CPU und hat auch eine Reihe anderer Warteereignisse. Hier ist der SQL-Text dieser Anweisungen.
SQL-ID:frjd8zfy2jfdq
SELECT
executions
,end_of_fetch_count
,elapsed_time / px_servers elapsed_time
,cpu_time / px_servers cpu_time
,buffer_gets / executions buffer_gets
FROM
(
SELECT
SUM (executions) AS executions
,SUM (
CASE
WHEN px_servers_executions > 0
THEN px_servers_executions
ELSE executions
END
) AS px_servers
,SUM (end_of_fetch_count) AS end_of_fetch_count
,SUM (elapsed_time) AS elapsed_time
,SUM (cpu_time) AS cpu_time
,SUM (buffer_gets) AS buffer_gets
FROM
gv$sql
WHERE
executions > 0
AND sql_id = : 1
AND parsing_schema_name = : 2
SQL-ID:4b4wp0a8dvkf0
SELECT
executions
,end_of_fetch_count
,elapsed_time / px_servers elapsed_time
,cpu_time / px_servers cpu_time
,buffer_gets / executions buffer_gets
FROM
(
SELECT
SUM (executions_delta) AS EXECUTIONS
,SUM (
CASE
WHEN px_servers_execs_delta > 0
THEN px_servers_execs_delta
ELSE executions_delta
END
) AS px_servers
,SUM (end_of_fetch_count_delta) AS end_of_fetch_count
,SUM (elapsed_time_delta) AS ELAPSED_TIME
,SUM (cpu_time_delta) AS CPU_TIME
,SUM (buffer_gets_delta) AS BUFFER_GETS
FROM
DBA_HIST_SQLSTAT s
,V$DATABASE d
,DBA_HIST_SNAPSHOT sn
WHERE
s.dbid = d.dbid
AND bitand (
nvl (
s.flag
,0
)
,1
) = 0
AND sn.end_interval_time > (
SELECT
systimestamp AT TIME ZONE dbtimezone
FROM
dual
) - 7
AND s.sql_id = : 1
AND s.snap_id = sn.snap_id
AND s.instance_number = sn.instance_number
AND s.dbid = sn.dbid
AND parsing_schema_name = : 2
)
)
Beide sind Teil der neuen Adaptive Query Optimization-Features jetzt in 12c. Genauer gesagt beziehen sich diese auf den Teil der automatischen dynamischen Statistik dieser Funktion. Die SQL-ID frjd8zfy2jfdq ist Oracle, das Informationen zur Leistung von SQL-Anweisungen von GV$SQL erhält. SQL-ID 4b4wp0a8dvkf0 ist Oracle, das dieselben Informationen zur Leistung von SQL-Anweisungen aus den Active Session History-Tabellen erhält.
Bertand Drouvot diskutiert dies hier in seinem Blog:https://bdrouvot.wordpress.com/2014/10/17/watch-out-for-optimizer_adaptive_features-as-it-may-have-a-huge-negative-impact/
Außerdem habe ich an einer Sitzung von Christian Antognini auf der Oak Table World 2015 teilgenommen, in der er diese SQL-Anweisungen erwähnt hat. Seine Folien von OTW sind so ziemlich die gleichen wie diese:
http://www.soug.ch/fileadmin/user_upload/SIGs/SIG_150521_Tuning_R/Christian_Antognini_AdaptiveDynamicSampling_trivadis.pdf
Diese Links oben und die MOS-Hinweise, auf die ich unten verweise, lieferten einen Großteil der Grundlage der Informationen, die ich hier präsentiere.
Alle Funktionen der adaptiven Abfrageoptimierung sollen das Leben des DBA verbessern. Sie sollen dem Optimierer helfen, bessere Entscheidungen zu treffen, selbst nachdem eine SQL-Anweisung mit der Ausführung begonnen hat. In diesem speziellen Fall sollen diese Abfragen dem CBO helfen, bessere Statistiken zu erhalten, selbst wenn die Statistiken fehlen. Dies kann helfen, die SQL-Leistung zu verbessern, aber wie ich in meinem Fall festgestellt habe, behindert es die Gesamtsystemleistung.
Weitere Informationen zur adaptiven Abfrageoptimierung finden Sie im Hinweis 2031605.1. Dies führt Sie zu anderen Hinweisen, insbesondere aber zu dieser Diskussion, Hinweis 2002108.1 Automatic Dynamic Statistics.
Erschwerend kommt hinzu, dass mein Produktionssystem, das dieses Verhalten sieht, Oracle RAC ist. Wenn die SQL-ID frjd8zfy2jfdq auf Oracle RAC-Systemen ausgeführt wird, wird eine parallele Abfrage verwendet, was aus meinem Screenshot durch die enq:PS – Konflikte und „PX%“ Warteereignisse ersichtlich ist.
Wir können das dynamische Sampling wie folgt ausschalten:
alter system set optimizer_dynamic_sampling=0 scope=both;
Der Standardwert dieses Parameters ist 2.
Für mich verbrauchen diese Abfragen Ressourcen und wirken sich auf die Gesamtleistung der Datenbank aus. Diese Funktionen sollen jedoch verbessert werden Leistung. Es besteht immer das Risiko, dass die Leistung in einem anderen Bereich beeinträchtigt wird, wenn ich die Funktion zur Verbesserung der Leistung in einem Bereich deaktiviere. Aber seit optimizer_dynamic_sampling<>11 für mich nutze ich diese Funktion nicht in vollem Umfang, sodass ich nicht alle Vorteile erhalte, die ich haben könnte. Außerdem ist unser Code nicht darauf angewiesen, dass dynamisches Sampling auftritt. Daher kann ich dies sicher deaktivieren.
Nachdem ich den Parameter geändert hatte, konnte ich eine sofortige Änderung sehen, wie unten gezeigt.
Die rote Linie zeigt den Zeitpunkt an, zu dem ich die Änderung vorgenommen habe. Es ist klar, dass die ASH-Version dieser Abfrage nicht mehr ausgeführt wird. Die V$SQL-Version wird weiterhin ausgeführt, sieht aber keine parallelen Abfragewarteereignisse mehr. Es verbraucht jetzt meistens nur CPU. Ich betrachte diesen Fortschritt aber nicht als vollständige Lösung.
Als Nebenbemerkung hätte ich alle Adaptive Query Optimization-Features mit folgendem abschalten können:
alter system set optimizer_adaptive_features=false scope=both;
Aber ich weiß, dass ich Abfragen habe, die Adaptive Join Optimization „genießen“, und ich möchte nicht alles ausschalten, sondern nur dynamisches Sampling.
Was also jetzt mit der SQL-ID frjd8zfy2jfdq tun? Mal sehen, ob wir das verbleibende Problem lösen können. Aus einem der oben verlinkten MOS-Hinweise weiß ich, dass wir diesen versteckten Parameter setzen können:
alter system set "_optimizer_dsdir_usage_control"=0 scope=both;
Der Standardwert für diesen versteckten Parameter war 126 in meinem 12.1.0.2-System. Ich habe die Standardeinstellung mit folgendem gefunden:
select a.ksppinm name, b.ksppstvl value, b.ksppstdf deflt,
from
sys.x$ksppi a,
sys.x$ksppcv b
where a.indx = b.indx
and a.ksppinm like '\_%' escape '\'
and a.ksppinm like '%dsdir%'
order by name;
Dieser Wert ist wichtig, falls ich ihn zurücksetzen möchte, ohne den Parameter aus der SPFILE nehmen zu müssen, was eine Ausfallzeit erfordern würde.
Ich kann jetzt damit fortfahren, diesen versteckten Parameter zu ändern und auf Null zu setzen. So sieht diese SQL-Anweisung in Lighty nach der Änderung aus:
Scheint „Mission erfüllt“ zu haben, indem er die Ausführung dieser beiden SQL-Anweisungen verhindert hat.
Diejenigen, die 12.1.0.2 auf Oracle RAC ausführen, möchten möglicherweise überprüfen, ob diese beiden SQL-Anweisungen keine eigenen Leistungsprobleme verursachen.
Dies scheint einer der Fälle zu sein, in denen eine Funktion, die die Leistung verbessern soll, tatsächlich das Gegenteil bewirkt.