Наскоро работех с човек по въпрос във форумите на MOSC, където те попитаха за TOP_LEVEL_RPI_CURSOR колоната на изгледа V$SQL_SHARED_CURSOR. Има малко документация за това, което тази колона се опитва да каже на DBA.
Всички документи на Oracle казват, че тази колона съдържа „(Y|N) е RPI курсор от най-високо ниво“. И така, какво означава това?
Предполагам, че читателят на тази публикация е запознат с детските курсори. Това ще ми спести голямо количество въвеждаща информация. Изгледът V$SQL_SHARED_CURSOR ще каже на DBA защо дъщерният курсор и неговият родител имат различни версии в споделения пул. Ако колоната OPTIMIZER_MISMATCH на дъщерния курсор съдържа „Y“ в този изглед, тогава сесията, изпълняваща курсора, е имала различни настройки на оптимизатора от сесията, която е била отговорна за изпълнението на родителския курсор.
И така, какво означава това, когато TOP_LEVEL_RPI_CURSOR е настроен на Y за дете? Документацията не е ясна. MOS има много малко по темата. И всичките ми попадения в Google в тази колона почти повръщат документацията. За да разберете защо, е полезно да знаете, че RPI е съкращение от Recursive Program Interface. Това е част от ядрото на Oracle, което се занимава с рекурсивния SQL. В нашия случай той се занимава с факта, че SQL изявлението е издадено на различна „дълбочина“.
Какво е рекурсивен SQL? Това е SQL, който се издава от ваше име, което означава на различна дълбочина, както ще илюстрирам. Първо, Oracle изпълнява рекурсивен SQL през цялото време. На основно ниво, когато издавате „select * from table_name“, Oracle отправя заявка към речника на данните, за да гарантира, че обектът съществува и че имате разрешения за тази таблица. Как Oracle прави това? Той използва други SQL изрази. Изявлението, което издавате, е на ниво 0, базовото ниво. Когато Oracle издаде SQL оператор, за да провери дали таблицата съществува, това ще бъде на следващото ниво, ниво 1. Понякога това ще доведе до издаване на други SQL оператори на следващото ниво, ниво 2.
Дълбочината на SQL израз не се ограничава само до това, което Oracle прави във фонов режим от ваше име. Помислете кога изпълнявате съхранена процедура. Вашето извикване към съхранената процедура е на дълбочина 0. Всеки SQL израз в съхранената процедура е на дълбочина 1. Ако тази съхранена процедура извика друга процедура, SQL в другата процедура ще бъде на дълбочина 2.
Използвах тази информация за рекурсивния SQL и дълбочината на SQL, за да създам прост пример в моята база данни Oracle 12.1.0.2. Първо създадох съхранена процедура.
create or replace procedure my_sysdate as v_dt date; begin select sysdate into v_dt from dual; end; /
След това стартирах SQL*Plus сесия и започнах проследяване. Издадох същия SQL оператор и след това извиках моята процедура.
SQL> alter session set sql_trace=true;
Session altered.
SQL> SELECT SYSDATE FROM DUAL 2 /
SYSDATE --------- 05-APR-16
SQL> exec my_sysdate;
PL/SQL procedure successfully completed.
SQL> exit
Когато разгледах необработения файл за проследяване, открих двете извиквания към SYSDATE от DUAL, както следва:
РАЗБИРАНЕ В КУРСОР #140670990815296 len=24 dep=0 uid=9449 oct=3 lid=9449 tim=24905125014484 hv=124468195 ad=’81477be0′ DUC77BE0=’DUC77BE0′′′′′′′ sqlid′′
РАЗБИРАНЕ В КУРСОР #140670907623848 len=24 dep=1 uid=9449 oct=3 lid=9449 tim=24905129780963 hv=124468195 ad=’81477be0′ DUC77BE0=’DUC77BE0′′′′ ′′′ ′′ sqlid′′
Ако погледнете отблизо файла за проследяване, ще видите, че вторият на дълбочина=1 е пряк резултат от съхранената процедура. Забележете, че въпреки че моята съхранена процедура беше дефинирана с всички малки букви, SQL, издаден на дълбочина=1, беше изцяло с главни букви. В резултат на това, когато издадох същия SQL оператор директно в моята SQL*Plus сесия (на дълбочина=0), трябваше да използвам същата форма с главни букви на този израз, така че той да има същата стойност на SQL ID.
Файлът за проследяване също показва SQL ID. Вече мога да потърся V$SQL_SHARED_CURSOR за тази стойност на SQL ID и да покажа, че TOP_LEVEL_RPI_CURSOR е зададен за детето.
SQL> select sql_id,top_level_rpi_cursor from v$sql_shared_cursor where sql_id='c749bc43qqfz3';
SQL_ID T ------------- - c749bc43qqfz3 N c749bc43qqfz3 Y
Така че имаме нашето доказателство. Единствената разлика между тези два курсора е, че единият е дълбочината, от която са били изпълнени. Не съм сигурен защо Oracle се нуждае от това разграничение в споделения пул. Ако някой знае, нека ми пише.
Обикновено не ни интересуват няколко допълнителни версии, няколко дъщерни курсора за даден SQL ID. Ако вашият SQL израз има голям брой версии, това вероятно не се дължи на различните нива на дълбочина. Други причини биха били по-подходящи за това защо SQL изразът ще има голям брой дъщерни курсори, голям брой различни версии. Но това отговаря на въпроса какво ни казва тази колона.