Jeg arbejdede med en person på et spørgsmål i MOSC-fora for nylig, hvor de spurgte om TOP_LEVEL_RPI_CURSOR-kolonnen i V$SQL_SHARED_CURSOR-visningen. Der er lidt dokumentation for, hvad denne klumme forsøger at fortælle DBA.
Alt, hvad Oracle-dokumenterne siger, er, at denne kolonne indeholder "(Y|N) Is top level RPI cursor". Så hvad betyder det?
Jeg vil antage, at læseren af dette indlæg er bekendt med børnemarkører. Det vil spare mig for en stor mængde introduktionsinformation. V$SQL_SHARED_CURSOR-visningen vil fortælle DBA, hvorfor en underordnet markør og dens forælder har forskellige versioner i den delte pool. Hvis den underordnede markørs OPTIMIZER_MISMATCH kolonne indeholder et "Y" i denne visning, så havde den session, der udfører markøren, andre optimeringsindstillinger end den session, der var ansvarlig for den overordnede markørudførelse.
Så hvad betyder det, når TOP_LEVEL_RPI_CURSOR er indstillet til Y for et barn? Dokumentationen er ikke klar. MOS har meget lidt om emnet. Og alle mine Google-hits i denne klumme genopliver stort set dokumentationen. For at vide hvorfor, hjælper det at vide, at RPI står for Recursive Program Interface. Dette er en del af Oracle-kernen, der beskæftiger sig med rekursiv SQL. I vores tilfælde handler det om, at SQL-sætningen blev udstedt i en anden "dybde".
Hvad er rekursiv SQL? Det er SQL, der udstedes på dine vegne, hvilket betyder i en anden dybde, som jeg vil illustrere. For det første udfører Oracle rekursiv SQL hele tiden. På et grundlæggende niveau, når du udsteder "vælg * fra tabelnavn", forespørger Oracle Data Dictionary for at sikre, at objektet eksisterer, og at du har tilladelser til den tabel. Hvordan gør Oracle det? Den bruger andre SQL-sætninger. Den erklæring, du udsteder, er på niveau 0, grundniveauet. Når Oracle udsteder en SQL-sætning for at kontrollere, om tabellen eksisterer, vil det være på næste niveau, niveau 1. Nogle gange vil det medføre, at andre SQL-sætninger udsendes på næste niveau, niveau 2.
Dybden af en SQL-sætning er ikke begrænset til, hvad Oracle laver i baggrunden på dine vegne. Overvej, hvornår du udfører en lagret procedure. Dit kald til den lagrede procedure er på dybde 0. Enhver SQL-sætning i den lagrede procedure er på dybde 1. Hvis den lagrede procedure kalder en anden procedure, vil SQL'en i den anden procedure være på dybde 2.
Jeg brugte disse oplysninger om rekursiv SQL og SQL-dybde til at konstruere et simpelt eksempel i min Oracle 12.1.0.2-database. Først oprettede jeg en lagret procedure.
create or replace procedure my_sysdate as v_dt date; begin select sysdate into v_dt from dual; end; /
Jeg startede derefter en SQL*Plus-session og startede en sporing. Jeg udstedte den samme SQL-sætning, og så kaldte jeg min procedure.
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
Da jeg undersøgte den rå sporingsfil, fandt jeg de to opkald til SYSDATE fra DUAL som følger:
PARSERING I MARKØR #140670990815296 len=24 dep=0 uid=9449 oct=3 lid=9449 tim=24905125014484 hv=124468195 ad=’81477be0′ sqlid=9bDUc4c4c3DATUM q49bSELECT’c4c3DATUM sqliddVelZc3c4c3c3SqliddA
PARSERING I MARKØR #140670907623848 len=24 dep=1 uid=9449 oct=3 lid=9449 tim=24905129780963 hv=124468195 ad=’81477be0′ sqlid=9bDUc4c4c3DATUM q49bSELECT’c4c3Sqlid=Sqlidd3c4c4c3DATUM sqlidd3c4c3c3c
Hvis du ser på sporingsfilen nøje, vil du se, at den anden ved dybde=1 var et direkte resultat af den lagrede procedure. Bemærk, at selvom min lagrede procedure var defineret med små bogstaver, var SQL'en udstedt ved dybde=1 med store bogstaver. Som et resultat, da jeg udstedte den samme SQL-sætning direkte i min SQL*Plus-session (ved depth=0), var jeg nødt til at bruge den samme form med store bogstaver af den sætning, så den ville have den samme SQL ID-værdi.
Sporingsfilen viser også SQL ID. Jeg kan nu forespørge V$SQL_SHARED_CURSOR for den SQL ID-værdi og vise, at TOP_LEVEL_RPI_CURSOR er indstillet til barnet.
SQL> select sql_id,top_level_rpi_cursor from v$sql_shared_cursor where sql_id='c749bc43qqfz3';
SQL_ID T ------------- - c749bc43qqfz3 N c749bc43qqfz3 Y
Så der har vi vores bevis. Den eneste forskel mellem disse to markører er, at den ene var den dybde, hvorfra de blev udført. Jeg er ikke sikker på, hvorfor Oracle har brug for denne sondring i den delte pool. Hvis nogen ved det, så skriv til mig.
Normalt er vi ligeglade med et par ekstra versioner, et par underordnede markører for et givet SQL ID. Hvis din SQL-sætning har et højt antal versioner, så er det sandsynligvis ikke på grund af de forskellige dybdeniveauer. Andre grunde ville være mere relevante for, hvorfor en SQL-sætning ville have et højt antal underordnede markører, et højt antal forskellige versioner. Men dette besvarer spørgsmålet om, hvad den klumme fortæller os.