29.11.2012 Views

Oracle Nordic AppsDays - Skalinformation

Oracle Nordic AppsDays - Skalinformation

Oracle Nordic AppsDays - Skalinformation

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

T I P S & T R I C K S › d a t a b a s o p t i m e r i n g<br />

Stored outlines – när det var bättre förr (del 2)<br />

I förra numret berättade jag om när jag fick anledning för första<br />

gången att använda mig av stored outlines. Kunden hade<br />

en selectsats vars svarstid blev så pass mycket längre efter en<br />

uppgradering från 9.2.0 till 10.2.0 att det orsakade stora problem<br />

för affärsverksamheten. Det visade sig efter lite analys att<br />

tidstjuven var att en dold parameter (_push_join_union_view2)<br />

hade bytt default värde från false till true. Eftersom jag varken ville<br />

sätta parametern till false (det gamla värdet som den hade i 9.2.0)<br />

för hela instansen eller skapa en logon trigger som satte parametern<br />

för aktuell session och det gick inte heller att ändra på select:n för<br />

att lägga till hinten opt_param( ’_push_join_union_view2’ ’FALSE’),<br />

så återstod bara en lösning: stored outline eller ”plan stability” som<br />

det kallas i <strong>Oracle</strong>s performance tuning manual.<br />

Vad är stored outlines?<br />

Stored outline eller plan stability skyddar prestandan för en applikation<br />

så att den inte påverkas av förändringar i databasmiljön. Som<br />

t ex, förändringar av statistiken på objekt, förändringar av parametervärden,<br />

storleken på olika minnesstrukturer (som sort_area_size<br />

och hash_area_size) samt tillkomsten av nya index. Om en stored<br />

outline är skapat för att använda ett visst index och det indexet tas<br />

bort så kommer självklart prestandan att påverkas. Så man är inte<br />

skyddad mot att index tas bort. Hur hänger då execution plan stability<br />

och stored outline ihop? Jo, plan stability lagrar den kompletta<br />

exekveringsplanen i stored outlines. En stored outline är implementerad<br />

som en grupp hintar för en specifik SQL sats. Om en stored<br />

outline är aktiv för en SQL sats så kommer <strong>Oracle</strong> automatiskt att<br />

utgå från dessa hintar och använda sig av de när optimeraren skapar<br />

exekveringsplanen för den SQL satsen.<br />

Om du använder dig av bind variabler så tänk på att det råder ett<br />

ett-till-ett förhållande mellan en SQL sats och en stored outline.<br />

Vilket betyder att om du använder dig av olika värden i ett villkor<br />

så behöver du ha en stored outline per värde (eller använda dig av<br />

bind variabler).<br />

Sätter man parametern cursor_sharing till force eller similar (jag<br />

rekommenderar starkt att man aldrig sätter den till similar) så hindrar<br />

man outlines, som innehåller konstanta värden och som var<br />

skapade med cursor_sharing satt till exact, från att användas. För<br />

att använda outlines med cursor_sharing satt till force så måste<br />

cursor_sharing var satt till force - samt att man satt create_stored_outlines<br />

parametern - när man skapar outline.<br />

<strong>Oracle</strong> använder sig av tre dictionary tabeller för att lagra informationen<br />

om stored outlines: ol$, ol$hints och ol$nodes. Om<br />

dessa tabeller ligger i system tablespace och man kommer att skapa<br />

många stored outlines så är det värt att flytta dessa tabeller till<br />

ett annat tablespace (antingen ett eget eller sysaux).<br />

Det finns fyra publika vyer: DBA|USER_OUTLINES och<br />

DBA|USER_OUTLINE_HINTS. I tabell 1 ser ni hur DBA vyerna är<br />

beskrivna i referensmanualen.<br />

Hur kan man se om en outline har använts? Så fort en outline har<br />

använts så sätts dba_outlines.used till USED. Ligger SQL:n kvar i<br />

library cache:n (sql arean) så kan visa den genom att köra select *<br />

from v$sql where outline_category = ’’; Kör man<br />

explain plan (eller något motsvarande kommando) så innehåller<br />

plan_table.remarks; vilket visas om man sedan kör dbms_xplan för<br />

att få se exekveringsplanen.<br />

Jag ska nu visa hur jag gick till vägen för att knyta en viss exekve-<br />

ringsplan till en viss stored outline. Detta kommer jag att visa på en<br />

tabell i min databas för att inte visa avslöja någon kundinformation.<br />

Se tabell 3.<br />

1DBA_OUTLINES<br />

Column Datatype Description<br />

Name Varchar2(30) User-specified or generated name of the stored outline.<br />

Owner Varchar2(30) Name of the user who created the outline.<br />

Category Varchar2(30) User-definied name of the category to which the outline<br />

belongs.<br />

Used Varchar2(6) Indicates whether the outline has ever been used (USED)<br />

or not (UNUSED).<br />

Timestamp Date Timestamp of outline creation.<br />

Version Varchar2(64) <strong>Oracle</strong> version that created the outline.<br />

Sql_text Long SQL text of the query, including any hints that were a part<br />

of the original statement. If bind variables are included, the<br />

variable names are stored as SQL text, not the values that<br />

are assigned to the variables.<br />

Signature Raw(16) Signature uniquely identifying the outline SQL text.<br />

Compatible Varchar2(12) Indicates whether the outline hints were compatible across<br />

a migration (COMPATIBLE) or not (INCOMPATIBLE).<br />

Enabled Varchar2(8) Indicates whether the outline is enabled (ENABLED) or<br />

disabled (DISABLED).<br />

Format Varchar2(6) Normal or local<br />

2DBA_OUTLINE_HINTS<br />

Column Datatype Description<br />

Name Varchar2(30) Name of the outline.<br />

Owner Varchar2(30) Name of the user who created the outline.<br />

Node Number ID of the query or subquery to which the hint applies. The<br />

top-level query is labeled 1. Subqueries are assigned<br />

sequentially numbered labels, starting with 2.<br />

Stage Number Outline hints can be applied at three different stages during<br />

the compilation process. This column indicates the stage at<br />

which the hint as applied.<br />

Join_pos Number Position of the table in the join order. The value is 0 for all<br />

hints except access method hints, which identify a table to<br />

which this hint was applied.<br />

Hint Varchar2(512) Text of the hint.<br />

3Skapa<br />

outline och bytt dess exekveringsplan mot den vi önskar<br />

Först måste jag hitta SQL:ns hash_value och child_number:<br />

SELECT hash_value hv, child_number cno, executions x, outline_category,<br />

parsing_schema_name psn<br />

FROM v$sql<br />

WHERE sql_text = ’SELECT * FROM OBJECTS WHERE OBJECT_NAME = :B1’;<br />

HV CNO X OUTLINE_CATEGORY PSN<br />

1761605448 0 1 JOCKE<br />

Sedan skapar jag en outline för original SQLen. Detta gör jag för att jag behöver fånga dess<br />

signatur m m.<br />

ALTER SESSION SET create_stored_outlines = ’NATTBATCH’;<br />

EXECUTE dbms_outln.create_outline( 1761605448, 0, ’NATTBATCH’ )<br />

ALTER SESSION SET create_stored_outlines = FALSE;<br />

Nu har jag en stored outline med ett systemgenererat namn och som ligger i kategorin<br />

nattbatch. Så nu skapar jag en stored outline för en SQL som genererar den exekveringsplan<br />

som jag vill ha. I mitt fall så kunde jag inte lösenordet till användaren JOCKE men eftersom jag<br />

körde som SYS så satte jag om aktuellt schema. Denna outline ger jag ett vettigt namn som jag<br />

själv hittar på men kategorin sätter jag till TEMP (lägg den inte i samma kategori som original<br />

SQLen).<br />

ALTER SESSION SET current_schema = jocke;<br />

CREATE OR REPLACE PUBLIC OUTLINE get_object FOR CATEGORY temp ON<br />

SELECT /*+ OPT_PARAM( ’_push_join_union_view2’ ’FALSE’ ) */ *<br />

FROM objects WHERE object_name = :B1;<br />

ALTER SESSION SET current_schema = sys;<br />

SELECT hintcount, ol_name, category, signature FROM outln.ol$<br />

WHERE category IN( ’NATTBATCH’, ’TEMP’ );<br />

Hintcount<br />

8 SYS_OUTLI-<br />

NE_09021600210254602<br />

Ol_name Category Signature<br />

NATTBATCH 924FD0857B3C2A07B98A-<br />

3E4D6FD50409<br />

9 GET_OBJECT TEMP 241F818600BC6A6D9442AC<br />

9F0C6391C3<br />

Hur ser det ut i OL$HINTS tabellen:<br />

SELECT ol_name, COUNT( * ) FROM outln.ol$hints GROUP BY ol_name;<br />

OL_NAME COUNT(*)<br />

SYS_OUTLINE_09021600210254602 8<br />

GET_OBJECT 9<br />

Nu har SYS_OUTLINE_nnn den signatur som applikationen använder sig av men fel<br />

exekveringsplan och GET_OBJECT har rätt exekveringsplan men en signatur som gör så att<br />

applikationen aldrig kommer att välja den. Så jag ska nu byta namn på dessa två outlines<br />

samt sätta hintcount till 9 (eftersom önskad exekveringsplan har 9).<br />

UPDATE outln.ol$<br />

SET ol_name = DECODE( ol_name, ’GET_OBJECT’, ’SYS_OUTLINE_09021600210254602’,<br />

’GET_OBJECT’ ),<br />

hintcount = 9 -- Här sätter vi det värde som tillhör den SQL som har rätt/önskad<br />

exekveringsplan<br />

WHERE ol_name IN( ’GET_OBJECT’, ’SYS_OUTLINE_09021600210254602’ );<br />

Ni kanske undrar varför jag inte använder DECODE på hintcount kolumnen? Nu blir det ju fel!<br />

Men det är ingen fara. Eftersom den outline som vi har kvar det gamla hintcount på kommer<br />

vi snart att ta bort. Skulle vi använda oss av DECODE på hintcount och sätta värdena i fel<br />

ordning så blir det inte så kul. Hur ser det ut nu innan vi gör commit?<br />

SELECT hintcount, ol_name, category, signature<br />

FROM outln.ol$<br />

WHERE category IN( ’NATTBATCH’, ’TEMP’ );<br />

Hintcount Ol_name Category Signature<br />

9 GET_OBJECT NATTBATCH 924FD0857B3C2A07B98A-<br />

3E4D6FD50409<br />

9 SYS_OUTLI-<br />

NE_09021600210254602<br />

TEMP 241F818600BC6A6D9442AC9<br />

F0C6391C3<br />

Nu tillhör outline GET_OBJECT kategorin NATTBATCH, har rätt signatur och nio hintar under sig<br />

i OL$HINTS.<br />

d a t a b a s o p t i m e r i n g › T I P S & T R I C K S<br />

20 21<br />

COMMIT;<br />

Nu tar vi bort den outline som är kopplad till den gamla exekveringsplanen:<br />

DROP PUBLIC OUTLINE SYS_OUTLINE_09021600210254602;<br />

Vi skapar en logon trigger för alla som loggar på som JOCKE och som sätter parametern<br />

use_stored_outlines till nattbatch. Sedan flushar vi shared pool så att all SQL måste hård<br />

parsas och på så sätt tvinga optimeraren att skapa nya exekveringsplaner.<br />

CREATE OR REPLACE TRIGGER jocke.after_logon_enable_ol<br />

AFTER LOGON ON jocke.SCHEMA<br />

BEGIN<br />

EXECUTE IMMEDIATE ’alter session set use_stored_outlines = nattbatch’;<br />

END;<br />

/<br />

ALTER SYSTEM FLUSH shared_pool;<br />

Vi ser till att någon kör applikationen så att vi kan kolla om den problematiska SQLen hittar<br />

vår outline.<br />

SELECT hash_value hv, child_number cno, executions x, outline_category,<br />

parsing_schema_name psn<br />

FROM v$sql<br />

WHERE sql_text = ’SELECT * FROM OBJECTS WHERE OBJECT_NAME = :B1’;<br />

HV CNO X OUTLINE_CATEGORY PSN<br />

1761605448 0 1 NATTBATCH JOCKE<br />

Anledningen till att antalet exekveringar visar ett är för att när jag flushade shared pool så<br />

försvann SQLen och all dess statistik från library cachen. När applikationen sedan parsade<br />

och körde frågan så laddades SQLen in med sina nya exekveringsplan. Så statistiken visar att<br />

frågan har körts en gång sedan den laddades in i librarycachen.<br />

Jag rekommenderar för den som vill veta mer att läsa kapitel 20,<br />

Using Plan Stability, i manualen <strong>Oracle</strong> Database Performance Tuning<br />

Guide.<br />

I 11g vill <strong>Oracle</strong> att man ska gå över och börja använda SQL plan<br />

management som i sin tur skapar SQL plan baselines, som visst<br />

ska vara mycket bättre när det gäller både prestanda och stabilitet.<br />

Har du redan stored outlines så kan du migrera dem till SQL<br />

plan baselines genom att köra någon av procedurerna load_plans_<br />

from_cursor_cache eller load_plans_from_sqlset som bägge ligger<br />

i paketet dbms_spm.<br />

Jocke Treugut jobbar på Aircom<br />

International med design, utveckling<br />

och optimering av data<br />

warehouse åt telekomföretag<br />

runt om i världen. Han driver<br />

också sitt egna konsultföretag<br />

Treugut Tuning & Learning AB<br />

som har specialiserat sig på<br />

prestandaproblem, resursoptimering,<br />

problemlösning, troubleshooting,<br />

skriva effektiv SQL och PL/SQL, utbildning/coaching<br />

av DBA:er/utvecklare, samt allt annat internt och hemligt i<br />

<strong>Oracle</strong>. Han har varit teknisk granskare för följande böcker: Optimizing<br />

<strong>Oracle</strong> Performance, Cary Millsap och Mastering <strong>Oracle</strong><br />

SQL and SQL*Plus, Lex De Haan. Han är medlem i the OakTable<br />

Network (www.oaktable.net). Mejla gärna vad du vill läsa om i<br />

kommande nummer till Jocke@Treugut-Tuning.com.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!