News zu Oracle

DBA Tipp: Cursor-Sharing-Kan­­di­­da­­ten in der Anwendung identifizieren

Cursor Sharing hat zwei­fel­los eine große Bedeutung für die Per­for­mance, ins­be­son­de­re das Vermeiden des Hard Parsing. Auf den ersten Blick nicht of­fen­sicht­lich, kann das Vorhalten vieler nicht-wie­der­ver­wend­ba­rer State­ments im Library Cache aber auch zur Ver­schwen­dung von Buffer Cache führen. Wie du Cursor-Sharing-Kan­di­da­ten in deiner Datenbank findest und welche zwei Mög­lich­kei­ten dir zur Op­ti­mie­rung zur Verfügung stehen, zeigt dieser DBA Tipp.

Logo Oracle Database

Cursor-Sharing da­ten­bank­weit erzwingen

Oracles Dia­gno­se­tools AWR und statspack speichern in ihren Re­po­si­to­ries neben Aus­füh­rungs­sta­tis­ti­ken auch Aus­füh­rungs­plä­ne ab. Diese werden regulär per INSERT-SELECT aus ent­spre­chen­den Data Dic­tion­a­ry-Views in die Re­po­si­to­ries über­tra­gen. Je mehr State­ments sich im Shared Pool befinden, desto mehr SELECT-State­ments werden aus­ge­führt und ent­spre­chend Da­ten­blö­cke durch den Buffer Cache ge­schleust. Das verdrängt unter Umständen in großem Umfang Da­ten­blö­cke, die für die ei­gent­li­che Da­ten­bank­an­wen­dung dort gepuffert waren und per­for­man­ce­re­le­vant wären.

Zudem haben wir oft be­ob­ach­tet, dass ver­gleichs­wei­se große Shared Pools mit sehr vielen nicht-wie­der­ver­wend­ba­ren State­ments zu einer erhöhten Anzahl von „library cache: mutex X“ oder „library cache pin“ Wait-Events führen. Du kannst Cursor Sharing an der Anwendung vorbei da­ten­bank­weit mit dem Parameter CURSOR_SHARING=FORCE erzwingen. In diesem Fall ersetzt die Datenbank von sich aus Literale in SQL-State­ments durch Bindevariablen.

Anpassung über Anwendungshersteller

Nicht alle An­wen­dungs­her­stel­ler gestatten das jedoch. Zum Teil gibt es auch Res­sen­ti­ments gegen diese Ein­stel­lung, die aus so­ge­nann­ten bind peeking Problemen aus Versionen vor 11.2.0.4, herrühren. Hat man ent­spre­chen­den Zugang zum Support des An­wen­dungs­ent­wick­lers, kann es daher von Interesse sein, ihm die konkreten State­ments mit­zu­tei­len, die wegen Verzicht auf Bin­de­va­ria­blen den Library Cache besonders exzessiv ver­schwen­den. Diese können dann in puncto Bin­de­va­ria­blen im Code angepasst werden.

Zu De­mons­tra­ti­ons­zwe­cken gehen wir von einem Szenario aus, in dem ein SELECT-Statement 10.000 Mal aus­ge­führt wird – jedes Mal mit einer anderen ID:

SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY, POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID = 1;
SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY, POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID = 2;
...
SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY, POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID = 9999;
SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY, POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID = 10000;

NAME                                                VALUE

---------------------------------------------- ----------
execute count                                       10351
parse count (describe)                                  0
parse count (failures)                                  0
parse count (hard)                                  10037
parse count (total)                                 10200
parse time cpu                                        677
parse time elapsed                                    648

Wie­der­ver­wend­ba­re State­ments erstellen

Wie unschwer zu erkennen ist, könnte dieses Statement durch Ersetzen des Literals für CUSTOMER_ID zu einem wie­der­ver­wend­ba­ren Statement ab­ge­än­dert werden. Statt 10.000 Hard Parses mit je einer Aus­füh­rung, wäre dann nur noch 1 Hard Parse er­for­der­lich. Das geparste Statement könnte dann die nächsten 9999 Mal wie­der­ver­wen­det werden und würde erheblich res­sour­cen­spa­ren­der arbeiten. Ob das über den Da­ten­bank­pa­ra­me­ter CURSOR_SHARING=FORCE oder durch Änderung der Anwendung erfolgt, ist hierbei letztlich unerheblich.

SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY, POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID = :ID;

NAME                                                 VALUE
----------------------------------------------- ----------
execute count                                        10015
parse count (describe)                                   0
parse count (failures)                                   0
parse count (hard)                                      39
parse count (total)                                  10201
parse time cpu                                          81
parse time elapsed                                      67

Auffinden der Cursor-Sharing-Kandidaten

Zum Auffinden solcher „tu­nens­wer­ter“ State­ments in einer Datenbank bedient man sich der Data-Dic­tion­a­ry-View v$sql. Sie führt zu jedem gecachten Statement in der Spalte FORCE_MATCHING_SIGNATURE eine Signatur seines Äqui­va­lents bei Ver­wen­dung von CURSOR_SHARING=FORCE mit. Die Anzahl der Einträge in v$sql mit jeweils gleicher Signatur ist also ein gutes Maß dafür, wie viele Aus­prä­gun­gen eines State­ments im Cache liegen, nur weil un­ter­schied­li­che Literale verwendet wurden.

In unserem Beispiel würde das Ergebnis aus der v$sql ohne Cur­sor­sha­ring in etwa so aussehen:

select force_matching_signature,count(*) anzahl
from v$sql
group by force_matching_signature
order by 2;


FORCE_MATCHING_SIGNATURE 	ANZAHL
------------------------ ----------
 	1253587301725552198     2
 	7928100255923163774     2
	17867806445150202466    3
	10927028642624449365    3
 	5494157341192764346     3
	11682584117507924582    3
	17301900507670644855    3
	17274913944183326537    3
   	    	0    121
 	8094602905134864270  	10000

In unserem Testfall ist das unterste Statement mit der höchsten Aus­prä­gung (10.000 Einträge mit der gleichen FORCE_MATCHING_SIGNATURE 8094602905134864270) vor­der­grün­dig in­ter­es­sant. Mit einigen Samples könnten wir uns jetzt ein un­ge­fäh­res Bild ver­schaf­fen, um welche State­ments es sich handelt:

select sql_text from v$sql
where force_matching_signature=8094602905134864270
fetch first 5 rows only;


SQL_TEXT
----------------------------------------------------------------------------------------------------
SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY,
POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID =9933


SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY,
POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID =8082


SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY,
POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID =2080


SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY,
POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID =6237


SELECT ADDRESS_ID, CUSTOMER_ID, DATE_CREATED, HOUSE_NO_OR_NAME, STREET_NAME, TOWN, COUNTY, COUNTRY,
POST_CODE, ZIP_CODE FROM ADDRESSES WHERE CUSTOMER_ID =7514

Fazit

State­ments, die Literale statt Bindva­lues verwenden, können sich durch erhöhten Par­se­auf­wand und Ver­schwen­dung von Library und auch Buffer Cache negativ auf die Per­for­mance auswirken. Ist eine globale Lösung durch Ver­wen­dung des Da­ten­bank­pa­ra­me­ters CURSOR_SHARING=FORCE nicht möglich, können die po­ten­ti­ell pro­ble­ma­ti­schen State­ments dynamisch ermittelt und so dem An­wen­dungs­her­stel­ler für eine gezielte Anpassung mit­ge­teilt werden.

Hier findest du weitere Infos rund um Oracle aus unserem News & Insights Bereich.

icon-arrow_right_medium-violet-blue.svg

Share this article

Facebook 
Twitter 
LinkedIn 
XING 
WhatsApp 
Email