Upload
sage-computing-services
View
24
Download
1
Embed Size (px)
Citation preview
www.sagecomputing.com.au
Transformations – how
Oracle rewrites your
statements
Penny Cookson SAGE Computing Services
SAGE Computing Services
Customised Oracle Training Workshops and Consulting
Agenda
How to identify transformations
Join Factorisation
Join Elimination
Other Transformations
Effect on Parse Time
Queries in the Select
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 10g:
ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SESSION
SET TRACEFILE_IDENTIFIER = ‘events_10053_1’;
ALTER SESSION
SET EVENTS ‘10053 trace name context forever’;
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 10g:
Parse the statement:-
SELECT * FROM organisations WHERE postcode = 6000
View the trace file
ALTER SESSION
SET EVENTS ‘10053 trace name context off’
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 11g:
ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SESSION
SET TRACEFILE_IDENTIFIER = ‘events_10053_2’;
ALTER SESSION
SET EVENTS
‘trace[rdbms.SQL_Optimizer.*][sql:40038fgx69y23]’;
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 11g:
Execute the statement:-
SELECT * FROM organisations WHERE postcode = 6000;
View the trace file
ALTER SESSION
SET EVENTS ‘trace[rdbms.SQL_Optimizer.*] off’;
Identifying Transformations –
Tracing the Optimizer’s decisions
More examples:
ALTER SESSION
SET EVENTS
‘trace[rdbms.SQL_Transform.*][sql:40038fgx69y23]’;
Trace file smaller
Transformations, session optimizer settings and bug fixes only
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 11g using DBMS_SQL_DIAG:
Automatically hard parse the statement
BEGIN
dbms_sqldiag.dump_trace (p_sql_id => '40038fgx69y23'
,p_child_number => 0
,p_component => 'Compiler'
,p_file_id => 'events_10053_4');
END;
/
View the trace file dbmsdiag.sql
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 11g using DBMS_SQL_DIAG: Is bind aware
DECLARE
v2 number;
cursor c1 (p_code in resources.code%type) is
SELECT /*+BIND_AWARE */ COUNT(l.quantity) FROM train1.bookings_large l WHERE
resource_code = p_code;
BEGIN
open c1 ('PC2');
fetch c1 into v2;
close c1;
open c1 ('BRLG');
fetch c1 into v2;
close c1;
END;
/
Identifying Transformations –
Tracing the Optimizer’s decisions
Oracle 11g using DBMS_SQL_DIAG: Is bind aware
BEGIN
dbms_sqldiag.dump_trace (p_sql_id => '463fjw7fvwmq6'
,p_child_number => 0
,p_component => 'Compiler'
,p_file_id => 'events_10053_11');
END;
/
BEGIN
dbms_sqldiag.dump_trace (p_sql_id => '463fjw7fvwmq6'
,p_child_number => 1
,p_component => 'Compiler'
,p_file_id => 'events_10053_12');
END;
/
View the 11 trace file View the 12 trace file
ALTER SESSION
SET EVENTS ‘trace[rdbms.SQL_Optimizer.*] off’;
Join Factorization
TABLE_A
TABLE_A
TABLE_B
TABLE_B
TABLE_C
TABLE_D
UNION ALL
Join Factorization
TABLE_A
TABLE_B
TABLE_B
TABLE_C
TABLE_D
UNION ALL
Join Factorization
alter session set optimizer_features_enable = '11.1.0.7'
SELECT e.description, b.booking_no, b.cost
FROM events_large e, bookings_large b, internal_organisations oi
WHERE e.event_no = b.event_no
AND e.org_id = oi.org_id
AND oi.state = 'WA'
UNION ALL
SELECT e.description, b.booking_no, b.cost
FROM events_large e, bookings_large b, external_organisations oe
WHERE e.event_no = b.event_no
AND e.org_id = oe.org_id
AND oe.state = 'WA'
Version 11.1
Join Factorization
alter session set optimizer_features_enable = '11.2.0.3'
SELECT e.description, b.booking_no, b.cost
FROM events_large e, bookings_large b, internal_organisations oi
WHERE e.event_no = b.event_no
AND e.org_id = oi.org_id
AND oi.state = 'WA'
UNION ALL
SELECT e.description, b.booking_no, b.cost
FROM events_large e, bookings_large b, external_organisations oe
WHERE e.event_no = b.event_no
AND e.org_id = oe.org_id
AND oe.state = 'WA'
Join Factorization
Manual Join Factorization
alter session set optimizer_features_enable = '11.1.0.7'
SELECT evt.description, b.booking_no, b.cost
FROM bookings_large b,
(SELECT e.description, e.event_no
FROM events_large e, internal_organisations oi
WHERE e.org_id = oi.org_id
AND oi.state = 'WA'
UNION ALL
SELECT e.description, e.event_no
FROM events_large e, external_organisations oe
WHERE e.org_id = oe.org_id
AND oe.state = 'WA') evt
WHERE evt.event_no = b.event_no
Manual Join Factorization
How to Avoid Stuffing It Up
UNION (RATHER THAN UNION ALL)
DISTINCT
OUTER JOINS
Join Factorization – This is OK
TABLE_A
TABLE_A
TABLE_B
TABLE_B
TABLE_C
TABLE_D
UNION ALL
(+)
(+)
Join Factorization – This is not OK
TABLE_A
TABLE_A
TABLE_B
TABLE_B
TABLE_C
TABLE_D
UNION ALL
(+)
(+)
(+)
(+)
Join Elimination
Oracle will get rid of joined tables if:
We give it indexes it can use instead
The PK and/or FK relationships imply a table is not required
Its done this for a long time
SELECT b.booking_no, b.resource_code
FROM bookings_large b, events_large e
WHERE b.event_no = e.event_no
AND e.contact_name like 'JOSIE%'
Why constraints are a good idea
SELECT e.description
FROM events e, organisations o
WHERE e.org_id = o.org_id
Constraints matter – they tell the optimiser stuff
Without a foreign key constraint
SELECT e.description
FROM events e, organisations o
WHERE e.org_id = o.org_id
ALTER TABLE events DISABLE
CONSTRAINT org_fk
Without a foreign key constraint
Use RELY for Warehouses
SELECT e.description
FROM events e, organisations o
WHERE e.org_id = o.org_id
ALTER TABLE events MODIFY
CONSTRAINT org_fk RELY;
Join Elimination - this is also OK
SELECT e.description, o.org_id
FROM events e, organisations o
WHERE e.org_id = o.org_id
This won’t do join elimination
SELECT e.description
FROM event_state e, org_state o
WHERE e.org_id = o.org_id
AND e.state = o.state
Multi column primary keys don’t do
Join Elimination
SELECT e.description
FROM event_state e, org_state o
WHERE e.org_id = o.org_id
AND e.state = o.state
SELECT *
FROM user_cons_columns
WHERE constraint_name = 'EVTST_ORG_FK'
Multi column primary keys don’t do
Join Elimination
SELECT e.description
FROM event_state e, org_state o
WHERE e.org_id = o.org_id
SELECT *
FROM user_cons_columns
WHERE constraint_name = 'EVTST_ORG_FK'
Use artificial
sequence
numbers for
Primary Keys
Join Elimination
So who would write that rubbish?
Useful with views where lots of columns are included but not
all selected from the view
Means views with a whole load of unnecessary stuff are not
so bad now
And we have View Merging transformations
CREATE VIEW pretty_stuff_for_users
AS
SELECT o.org_id, o.name,
e.event_no, e.description event_description,
e.start_date, r.description resource_description,
b.booking_no, b.cost, b.quantity, b.resource_code
FROM organisations o, events e, bookings b, resources r
WHERE o.org_id = e.org_id
AND e.event_no = b.event_no
AND b.resource_code = r.code
SELECT booking_no, cost, quantity,
resource_code, resource_description
FROM pretty_stuff_for_users
SELECT e.description
FROM events e, organisations o
WHERE e.org_id = o.org_id
ALTER TABLE events modify (org_id not null)
SELECT booking_no, cost, quantity,
resource_code, resource_description
FROM pretty_stuff_for_users
Join Factorization
Join Factorization
If a column is not
null define it as
NOT NULL
10G – JOIN before the GROUP BY
11G – GROUP BY before the JOIN
10G – NOT IN (PROMISE_NO NULLABLE)
10G – KILLED AFTER 1 hr
11G – Rewrite as Null Aware Anti join
10G – Full Outer Join – default behaviour
From version 10.2.0.3
SELECT /*+ NATIVE_FULL_OUTER_JOIN */
count(e.comments) nume,
count (b.comments) numb
FROM events_large e
FULL OUTER JOIN bookings_large b
ON (e.event_no = b.event_no)
10G – Full Outer Join – hint
11G Native Full Outer Join
SELECT b.booking_no, b.cost, b.quantity,
(SELECT description FROM resources r
WHERE r.code = b.resource_code)
FROM bookings_large b)
SELECT b.booking_no, b.cost, b.quantity,
r.description
FROM bookings_large b, resources r
WHERE b.resource_code = r.code
This is fine and will actually be
more efficient than this
(but may have a different result)
Queries in the SELECT
SELECT b.booking_no, b.cost, b.quantity,
(SELECT description FROM resources r
WHERE r.code = b.resource_code),
(SELECT type_code FROM resources r
WHERE r.code = b.resource_code),
(SELECT daily_rate FROM resources r
WHERE r.code = b.resource_code)
FROM bookings_large b)
This is really stupid and will access the
RESOURCES table multiple times
Queries in the SELECT
SELECT b.booking_no, b.cost, b.quantity,
booking_utl.get_stat1 (
(SELECT description FROM resources r
WHERE r.code = b.resource_code),
(SELECT type_code FROM resources r
WHERE r.code = b.resource_code),
(SELECT daily_rate FROM resources r
WHERE r.code = b.resource_code)),
booking_utl.get_stat2 (
(SELECT description FROM resources r
WHERE r.code = b.resource_code),
(SELECT type_code FROM resources r
WHERE r.code = b.resource_code),
(SELECT daily_rate FROM resources r
WHERE r.code = b.resource_code)),
FROM bookings_large b)
From a real example!!!
Much More Query Transformation SELECT e.event_no, e.start_date, sum(cost) totcost
FROM events_large e, bookings_large b
WHERE e.event_no = b.event_no
GROUP BY e.event_no, e.start_date
Oracle 10g – Run a whole load of random statements – all of
which require parsing
Oracle 11g – Run a whole load of random statements – all of
which require parsing
So Tuning the Shared
Pool becomes more
important,
but overall the 11g
CBO is pretty smart
Conclusion
Proper relational database design techniques are important
Views are OK
11g will do stuff 10g can’t – get rid of the hints
Developer are encouraged to do stupid stuff
Proper use of the shared pool is important
SAGE Computing Services
Customised Oracle Training Workshops and Consulting
Questions?
www.sagecomputing.com.au