Ik werkte onlangs met een persoon aan een vraag in de MOSC-forums waarin ze vroegen naar de kolom TOP_LEVEL_RPI_CURSOR van de weergave V$SQL_SHARED_CURSOR. Er is weinig documentatie over wat deze column de DBA probeert te vertellen.
Alle Oracle-documenten zeggen dat deze kolom "(Y|N) Is RPI-cursor op het hoogste niveau" bevat. Dus wat betekent dat?
Ik ga ervan uit dat de lezer van dit bericht bekend is met kindcursors. Dat scheelt mij een hoop inleidende informatie. De weergave V$SQL_SHARED_CURSOR vertelt de DBA waarom een onderliggende cursor en zijn bovenliggende cursor verschillende versies hebben in de gedeelde pool. Als de OPTIMIZER_MISMATCH-kolom van de onderliggende cursor een 'Y' bevat in deze weergave, had de sessie die de cursor uitvoerde andere optimalisatie-instellingen dan de sessie die verantwoordelijk was voor de uitvoering van de bovenliggende cursor.
Dus wat betekent het als TOP_LEVEL_RPI_CURSOR is ingesteld op Y voor een kind? De documentatie is niet duidelijk. MOS heeft er weinig over. En al mijn Google-hits in deze kolom spuien eigenlijk gewoon de documentatie uit. Om te weten waarom, helpt het om te weten dat RPI staat voor Recursive Program Interface. Dit maakt deel uit van de Oracle-kernel die zich bezighoudt met recursieve SQL. In ons geval gaat het over het feit dat de SQL-instructie op een andere "diepte" is uitgegeven.
Wat is recursieve SQL? Het is SQL die namens u wordt uitgegeven, wat betekent op een andere diepte, zoals ik zal illustreren. Ten eerste voert Oracle de hele tijd recursieve SQL uit. Op een basisniveau, wanneer u "select * from table_name" opgeeft, doorzoekt Oracle de Data Dictionary om er zeker van te zijn dat het object bestaat en dat u machtigingen hebt voor die tabel. Hoe doet Oracle dat? Het gebruikt andere SQL-instructies. De verklaring die u afgeeft bevindt zich op niveau 0, het basisniveau. Wanneer Oracle een SQL-instructie uitgeeft om te controleren of de tabel bestaat, is dat op het volgende niveau, niveau 1. Soms zorgt dat ervoor dat andere SQL-instructies op het volgende niveau, niveau 2 worden uitgegeven.
De diepgang van een SQL-statement is niet beperkt tot wat Oracle namens u op de achtergrond doet. Overweeg wanneer u een opgeslagen procedure uitvoert. Uw aanroep van de opgeslagen procedure bevindt zich op diepte 0. Elke SQL-instructie in de opgeslagen procedure bevindt zich op diepte 1. Als die opgeslagen procedure een andere procedure aanroept, bevindt de SQL in de andere procedure zich op diepte 2.
Ik heb deze informatie over recursieve SQL en SQL-diepte gebruikt om een eenvoudig voorbeeld te maken in mijn Oracle 12.1.0.2-database. Eerst heb ik een opgeslagen procedure gemaakt.
create or replace procedure my_sysdate as v_dt date; begin select sysdate into v_dt from dual; end; /
Ik heb toen een SQL*Plus-sessie gestart en een tracering gestart. Ik heb dezelfde SQL-instructie uitgegeven en toen heb ik mijn procedure aangeroepen.
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
Toen ik het onbewerkte traceerbestand bekeek, vond ik de twee aanroepen naar SYSDATE van DUAL als volgt:
PARSING IN CURSOR #140670990815296 len=24 dep=0 uid=9449 oct=3 lid=9449 tim=24905125014484 hv=124468195 ad=’81477be0′ sqlid=’c749bc43qqfz3′ SELECTEER SYSDATE UIT DUAL
PARSING IN CURSOR #140670907623848 len=24 dep=1 uid=9449 oct=3 lid=9449 tim=24905129780963 hv=124468195 ad=’81477be0′ sqlid=’c749bc43qqfz3′ SELECTEER SYSDATE UIT DUAL
Als je het traceerbestand goed bekijkt, zul je zien dat de tweede op diepte=1 een direct gevolg was van de opgeslagen procedure. Merk op dat hoewel mijn opgeslagen procedure in kleine letters was gedefinieerd, de SQL die werd uitgegeven op depth=1 in hoofdletters was. Als gevolg hiervan moest ik, toen ik dezelfde SQL-instructie rechtstreeks in mijn SQL*Plus-sessie (op diepte=0) uitgaf, dezelfde hoofdletters van die instructie gebruiken, zodat deze dezelfde SQL-ID-waarde zou hebben.
Het trace-bestand toont ook de SQL-ID. Ik kan nu V$SQL_SHARED_CURSOR opvragen voor die SQL ID-waarde en laten zien dat TOP_LEVEL_RPI_CURSOR is ingesteld voor het kind.
SQL> select sql_id,top_level_rpi_cursor from v$sql_shared_cursor where sql_id='c749bc43qqfz3';
SQL_ID T ------------- - c749bc43qqfz3 N c749bc43qqfz3 Y
Dus daar hebben we ons bewijs. Het enige verschil tussen deze twee cursors is dat één de diepte was van waaruit ze werden uitgevoerd. Ik weet niet zeker waarom Oracle dit onderscheid in de Shared Pool nodig heeft. Als iemand het weet, stuur me dan een berichtje.
Normaal gesproken geven we niet om een paar extra versies, een paar onderliggende cursors voor een gegeven SQL-ID. Als uw SQL-instructie een groot aantal versies heeft, ligt dit waarschijnlijk niet aan de verschillende diepteniveaus. Andere redenen zouden relevanter zijn waarom een SQL-instructie een groot aantal onderliggende cursors en een groot aantal verschillende versies zou hebben. Maar dit beantwoordt wel de vraag wat die column ons vertelt.