След скорошна надстройка до 12.1.0.2, работих по редица проблеми с производителността. Много такива проблеми са свързани с лош SQL и редица проблеми, които разреших, доказах, че са проблеми в старата версия 11.2.0.4. Това просто означава, че винаги е бил проблем. Но хората се възползват от възможността на надстройката, за да ме накарат да поправя неща, които са били повредени от доста време.
Докато разглеждах проблемите с производителността, се натъкнах на два SQL оператора, които се превръщат в прасета в нашата система. Ето екранна снимка на двата SQL оператора, както се вижда в Lighty:
Можем да видим, че първият SQL израз (SQL ID 4b4wp0a8dvkf0) консумира процесора и чака четене от контролния файл. Вторият SQL израз (SQL ID frjd8zfy2jfdq) използва много CPU и има редица други събития за изчакване. Ето SQL текста на тези изрази.
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
)
)
И двете са част от новите функции за адаптивна оптимизация на заявки сега в 12c. По-конкретно, те се отнасят до частта за автоматична динамична статистика на тази функция. SQL ID frjd8zfy2jfdq е Oracle, получаващ информация за производителността на SQL изрази от GV$SQL. SQL ID 4b4wp0a8dvkf0 е Oracle, който получава същата информация за производителността на SQL изрази от таблиците с активна история на сесиите.
Bertand Drouvot обсъжда това в своя блог тук:https://bdrouvot.wordpress.com/2014/10/17/watch-out-for-optimizer_adaptive_features-as-it-may-have-a-huge-negative-impact/
Освен това участвах в сесия на Кристиан Антонини на Oak Table World 2015, където той спомена тези SQL изявления. Неговите слайдове от OTW са почти същите като тези:
http://www.soug.ch/fileadmin/user_upload/SIGs/SIG_150521_Tuning_R/Christian_Antognini_AdaptiveDynamicSampling_trivadis.pdf
Тези връзки по-горе и бележките на MOS, които посочвам по-долу, предоставят голяма част от основата на информацията, която представям тук.
Всички функции за адаптивна оптимизация на заявки трябва да направят живота на DBA по-добър. Те трябва да помогнат на оптимизатора да взема по-добри решения, дори след като SQL оператор е започнал да се изпълнява. В този конкретен случай тези заявки трябва да помогнат на CBO да получи по-добра статистика, дори ако статистиката липсва. Това може да помогне за подобряване на производителността на SQL, но както открих в моя случай, това пречи на цялостната производителност на системата.
За повече информация относно адаптивната оптимизация на заявки вижте бележка 2031605.1. Това ще ви отведе до други бележки, но по-специално до тази дискусия, Бележка 2002108.1 Автоматична динамична статистика.
Влошава нещата, че моята производствена система, която вижда това поведение, е Oracle RAC. Когато SQL ID frjd8zfy2jfdq се изпълнява на Oracle RAC системи, се използва паралелна заявка, което е очевидно от моя екранна снимка от enq:PS – конкуренция и „PX%“ чакащи събития.
Можем да включим динамичното вземане на проби, както следва:
променете системния набор optimizer_dynamic_sampling=0 обхват=и двете;
Стойността по подразбиране на този параметър е 2.
За мен тези заявки консумират ресурси и влияят върху цялостната производителност на базата данни. И все пак тези функции са предназначени да подобрят производителност. Винаги има риск, че ако изключа функцията, за да помогна на производителността в една област, това ще навреди на производителността в друга област. Но тъй като optimizer_dynamic_sampling<>11 за мен, аз не използвам тази функция докрай, така че не получавам всички предимства, които бих могъл да имам. Освен това нашият код не разчита на динамично вземане на проби. Така че е безопасно за мен да изключа това.
След промяна на параметъра можех да видя незабавна промяна, както е показано по-долу.
Червената линия показва часа, в който направих промяната. Ясно е, че ASH версията на тази заявка вече не се изпълнява. Версията на V$SQL все още се изпълнява, но вече не вижда събития за изчакване на паралелна заявка. Сега най-вече само консумира процесора. Считам този напредък, но не и пълно решение.
Като странична забележка, можех да изключа всички функции за адаптивно оптимизиране на заявки със следното:
alter system set optimizer_adaptive_features=false scope=both;
Но знам, че имам заявки, които се наслаждават на адаптивната оптимизация на присъединяването и не искам да изключвам всичко, а само динамично вземане на проби.
И така, какво да правим със SQL ID frjd8zfy2jfdq? Да видим дали можем да разрешим оставащия проблем. От една от MOS бележките, които свързах по-горе, знам, че можем да зададем този скрит параметър:
alter system set "_optimizer_dsdir_usage_control"=0 scope=both;
Стойността по подразбиране за този скрит параметър беше 126 в моята система 12.1.0.2. Намерих настройката по подразбиране със следното:
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;
Тази стойност е важна в случай, че искам да я задам обратно, без да се налага да изваждам параметъра от SPFILE, което ще изисква престой.
Сега мога да продължа с промяната на този скрит параметър и да го настроя на нула. Ето как изглежда този SQL израз в Lighty след промяната:
Изглежда, че „мисията е изпълнена“ в спирането на изпълнението на тези два SQL оператора.
Тези, които работят с 12.1.0.2 на Oracle RAC, може да искат да проверят дали тези два SQL оператора не причиняват собствени проблеми с производителността.
Това изглежда е един от онези случаи, когато функция, която трябва да помогне на производителността, всъщност прави обратното.