Efter en nyligen uppgradering till 12.1.0.2 har jag arbetat med ett antal prestandaproblem. Många sådana problem är relaterade till dålig SQL och ett antal problem som jag har löst som jag har bevisat var problem i den gamla 11.2.0.4-versionen. Detta betyder bara att det alltid har varit ett problem. Men folk tar tillfället i akt med uppgraderingen för att få mig att fixa saker som har varit trasiga ett bra tag.
När jag tittade på prestandaproblem har jag stött på två SQL-satser som håller på att bli svin i vårt system. Här är en skärmdump av de två SQL-satserna som ses i Lighty:
Vi kan se att den första SQL-satsen (SQL ID 4b4wp0a8dvkf0) förbrukar CPU och väntar på läsningar från kontrollfilen. Den andra SQL-satsen (SQL ID frjd8zfy2jfdq) använder massor av CPU och har ett antal andra väntehändelser också. Här är SQL-texten för dessa satser.
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
)
)
Båda dessa är en del av de nya Adaptive Query Optimization-funktionerna nu i 12c. Mer specifikt relaterar dessa till den automatiska dynamiska statistikdelen av den här funktionen. SQL ID frjd8zfy2jfdq är Oracle som hämtar information om SQL-satsprestanda från GV$SQL. SQL ID 4b4wp0a8dvkf0 är Oracle som hämtar samma information om SQL-satsprestanda från Active Session History-tabellerna.
Bertand Drouvot diskuterar detta på sin blogg här:https://bdrouvot.wordpress.com/2014/10/17/watch-out-for-optimizer_adaptive_features-as-it-may-have-a-huge-negative-impact/
Dessutom satt jag i en session av Christian Antognini på Oak Table World 2015 där han nämnde dessa SQL-satser. Hans bilder från OTW är i stort sett desamma som dessa:
http://www.soug.ch/fileadmin/user_upload/SIGs/SIG_150521_Tuning_R/Christian_Antognini_AdaptiveDynamicSampling_trivadis.pdf
Dessa länkar ovan och MOS-anteckningarna som jag refererar till nedan gav mycket av grunden för den information jag presenterar här.
Alla Adaptive Query Optimization-funktioner är tänkta att göra DBA:s liv bättre. De är tänkta att hjälpa Optimizern att fatta bättre beslut, även efter att en SQL-sats har börjat köras. I det här specifika fallet ska dessa frågor hjälpa CBO att få bättre statistik, även om statistiken saknas. Detta kan hjälpa till att förbättra SQL-prestandan, men som jag upptäckte i mitt fall hämmar det systemets övergripande prestanda.
För mer om adaptiv frågeoptimering, se anmärkning 2031605.1. Detta leder dig till andra anteckningar, men i synnerhet till denna diskussion, Note 2002108.1 Automatic Dynamic Statistics.
Det som gör saken värre är att mitt produktionssystem som ser detta beteende är Oracle RAC. När SQL ID frjd8zfy2jfdq utförs på Oracle RAC-system, används parallella frågor, vilket är uppenbart från min skärmdump av enq:PS – påstående och "PX%" vänta-händelser.
Vi kan stänga av dynamisk sampling enligt följande:
alter system set optimizer_dynamic_sampling=0 scope=both;
Standardvärdet för denna parameter är 2.
För mig tar dessa frågor upp resurser och påverkar databasens övergripande prestanda. Ändå är dessa funktioner utformade för att förbättras prestanda. Det finns alltid en risk att om jag stänger av funktionen för att hjälpa prestanda inom ett område, kommer det att skada prestandan inom ett annat område. Men eftersom optimizer_dynamic_sampling<>11 för mig, använder jag inte den funktionen till fullo så jag får inte alla fördelar jag skulle kunna vara. Dessutom är vår kod inte beroende av att dynamisk sampling ska ske. Så det är säkert för mig att stänga av det här.
Efter att ha ändrat parametern kunde jag se en omedelbar förändring som visas nedan.
Den röda linjen anger när jag gjorde ändringen. Det är tydligt att ASH-versionen av denna fråga inte längre körs. V$SQL-versionen körs fortfarande men ser inte längre parallella frågeväntningshändelser. Det förbrukar mest bara CPU nu. Jag anser detta framsteg, men inte som en fullständig upplösning.
Som en sidoanteckning kunde jag ha stängt av alla funktioner för Adaptive Query Optimization med följande:
alter system set optimizer_adaptive_features=false scope=both;
Men jag vet att jag har frågor som "njuter av" Adaptive Join Optimization och jag vill inte stänga av allt, bara dynamisk sampling.
Så nu vad ska jag göra med SQL ID frjd8zfy2jfdq? Låt oss se om vi kan lösa det återstående problemet. Från en av MOS-anteckningarna jag länkade ovan vet jag att vi kan ställa in denna dolda parameter:
alter system set "_optimizer_dsdir_usage_control"=0 scope=both;
Standardvärdet för denna dolda parameter var 126 i mitt 12.1.0.2-system. Jag hittade standardinställningen med följande:
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;
Det här värdet är viktigt om jag vill ställa tillbaka det utan att behöva ta bort parametern från SPFILE, vilket skulle kräva driftstopp.
Jag kan nu fortsätta med att ändra denna dolda parameter och ställa in den på noll. Så här ser den SQL-satsen ut i Lighty efter ändringen:
Ser ut att vara "uppdrag fullbordat" när det gäller att stoppa dessa två SQL-satser från att köras.
De som kör 12.1.0.2 på Oracle RAC kanske vill verifiera att dessa två SQL-satser inte orsakar sina egna prestandaproblem.
Det här verkar vara ett av de fall där en funktion som ska hjälpa prestanda faktiskt gör tvärtom.