Oracle Nordic AppsDays - Skalinformation
Oracle Nordic AppsDays - Skalinformation
Oracle Nordic AppsDays - Skalinformation
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.