Nedávno jsem pracoval s jednotlivcem na otázce na fórech MOSC, kde se ptali na sloupec TOP_LEVEL_RPI_CURSOR zobrazení V$SQL_SHARED_CURSOR. Existuje jen malá dokumentace o tom, co se tento sloupec snaží sdělit DBA.
Dokumenty Oracle říkají, že tento sloupec obsahuje „(Y|N) je kurzor RPI nejvyšší úrovně“. Co to tedy znamená?
Předpokládám, že čtenář tohoto příspěvku zná dětské kurzory. To mi ušetří velké množství úvodních informací. Zobrazení V$SQL_SHARED_CURSOR řekne správci databází, proč mají podřízený kurzor a jeho nadřazený kurzor různé verze ve sdíleném fondu. Pokud sloupec OPTIMIZER_MISMATCH podřízeného kurzoru obsahuje v tomto zobrazení „Y“, pak relace spouštějící kurzor měla jiná nastavení optimalizátoru než relace, která byla zodpovědná za spuštění nadřazeného kurzoru.
Co to tedy znamená, když je TOP_LEVEL_RPI_CURSOR pro dítě nastaveno na Y? Dokumentace není jasná. MOS má na toto téma velmi málo. A všechny mé zásahy Google do tohoto sloupce v podstatě jen vyvracejí dokumentaci. Chcete-li vědět proč, je dobré vědět, že RPI znamená Rekurzivní programové rozhraní. Toto je část jádra Oracle, které se zabývá rekurzivním SQL. V našem případě se jedná o to, že SQL příkaz byl vydán v jiné „hloubce“.
Co je rekurzivní SQL? Je to SQL, které je vydáváno vaším jménem, což znamená v jiné hloubce, jak uvedu. Za prvé, Oracle neustále provádí rekurzivní SQL. Na základní úrovni, když zadáte „select * from table_name“, Oracle se dotazuje Data Dictionary, aby se ujistil, že objekt existuje a že máte pro tuto tabulku oprávnění. Jak to Oracle dělá? Používá jiné příkazy SQL. Vydaný příkaz je na úrovni 0, základní úrovni. Když Oracle vydá příkaz SQL, aby zkontroloval, zda tabulka existuje, bude to na další úrovni, úrovni 1. Někdy to způsobí, že budou vydány další příkazy SQL na další úrovni, úroveň 2.
Hloubka příkazu SQL není omezena pouze na to, co Oracle dělá na pozadí vaším jménem. Zvažte při provádění uložené procedury. Vaše volání uložené procedury je v hloubce 0. Jakýkoli příkaz SQL v uložené proceduře je v hloubce 1. Pokud tato uložená procedura volá jinou proceduru, SQL v jiné proceduře bude v hloubce 2.
Tyto informace o rekurzivním SQL a hloubce SQL jsem použil k vytvoření jednoduchého příkladu v mé databázi Oracle 12.1.0.2. Nejprve jsem vytvořil uloženou proceduru.
create or replace procedure my_sysdate as v_dt date; begin select sysdate into v_dt from dual; end; /
Poté jsem spustil relaci SQL*Plus a spustil trasování. Vydal jsem stejný příkaz SQL a poté jsem zavolal svou proceduru.
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
Když jsem prozkoumal nezpracovaný trasovací soubor, našel jsem dvě volání SYSDATE z DUAL takto:
PARZOVÁNÍ V KURZORU #140670990815296 len=24 dep=0 uid=9449 oct=3 lid=9449 tim=24905125014484 hv=124468195 ad=’81477be0′3′49lid>FROMqDUz’cSYSTÉM PARZOVÁNÍ V KURZORU #140670907623848 len=24 dep=1 uid=9449 oct=3 lid=9449 tim=24905129780963 hv=124468195 ad=’81477be0′3DATUM>FqbDUz′49lid=SELECT'c34AL=SELECT
Pokud se na trasovací soubor podíváte pozorně, uvidíte, že druhý v hloubce=1 byl přímým výsledkem uložené procedury. Všimněte si, že i když byla moje uložená procedura definována malými písmeny, SQL vydaný v hloubce=1 byl velký. V důsledku toho, když jsem vydal stejný příkaz SQL přímo v mé relaci SQL*Plus (v hloubce=0), musel jsem použít stejnou formu velkých písmen tohoto příkazu, aby měl stejnou hodnotu SQL ID.
Trasovací soubor také zobrazuje ID SQL. Nyní mohu zadat dotaz V$SQL_SHARED_CURSOR na tuto hodnotu SQL ID a ukázat, že pro podřízeného je nastaveno 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
Takže tady máme důkaz. Jediný rozdíl mezi těmito dvěma kurzory je v tom, že jedním z nich byla hloubka, ze které byly provedeny. Nejsem si jistý, proč Oracle potřebuje toto rozlišení ve sdíleném fondu. Pokud někdo ví, napište mi.
Normálně se nestaráme o několik dalších verzí, několik podřízených kurzorů pro dané SQL ID. Pokud má váš příkaz SQL vysoký počet verzí, pravděpodobně to není způsobeno různými úrovněmi hloubky. Jiné důvody by byly relevantnější pro to, proč by příkaz SQL měl vysoký počet podřízených kurzorů, vysoký počet různých verzí. Ale to odpovídá na otázku, co nám tento sloupec říká.