Vous êtes sur la page 1sur 44

Oracle Tuning Tips And Tricks

UST Global GE Account

What is Tuning?

Tuning is an art requiring creativity

Tuning is a science requiring regimen

Thus, we must use both intuition and rules

Performance Pyramid
Network
Hardware OS

DBMS
Application

Where Should We Look?

When we look at the applications we will find mainly two reasons

a) Wrong Designs
b) ineffective SQLs written Do your developers know: Sub-queries (correlated and not) Outer Joins Minus Union and Union-All

Golden Rule #1: Its the application stupid!

When Can One start tuning?

When I write a Code.


When Issue is reported. As and When Required.

Tuning as you go may be impractical, and after youre done it may be too late. Often its best to apply general tuning guidelines as you go, and then identify problem areas for improvement.

Golden Rule #2: Best to tune before, during, and after!

Who will find the needle first?

Who will find the needle first?

Who will find the needle first?

Who will find the needle first?

Who will find the needle first?

Everyone Needs Tools So Do We

Everyone tune codes as per the knowledge they have developed with time. SQL Looks very simple but matter of fact is that even optimizer also work on intuition of the developers

Golden Rule #3: Utilize tools to tune SQL!

Now What

SQL Codes Must Watch PLSQL Codes Must Watch

SQL Codes Must Watch

Indexes
What are indexes? What are the type of Index available for me? How can they help me? What to Index ? What Not to Index ? Are they really good?

What are indexes?


An index is a data structure that takes the value of one or more columns of a table (the key) and returns all rows (or the requested columns in that row) with that value of the column quickly. The efficiency of the index is that it lets you find the necessary rows without having to perform a full table scan, this leads to few I/O's.

Various Types Of Indexes


B-Tree indexes Bitmap indexes

Cluster indexes, bitmap join indexes, function-based indexes, reverse key indexes and text indexes are all just variations on the two main types
What B-Stands in B-Tree?

How can they help me?


To quickly find specific rows by avoiding a Full Table Scan To avoid a table access altogether To avoid a sort

What to Index and What Not?


Should I Index each and every column. How to find which columns need to be indexed. What kind of index one need to create?

Are they really good?

Well the answer of this is bit trick. But still I will say sometimes indexes in oracle can get more scary then the monster we had seen in our dreams
Golden Rule #4: Use indexes but not with blind eye

Time To Watch your SQL Now


Rule #1: Watch Indexed WHERE Conditions
Assume index on address (city, state) non-leading index column references cannot use indexes where state = 'TX' where city = 'DALLAS' where state = 'TX' and city = 'DALLAS' NOT, != and <> disable index use where state not in ('TX', 'FL','OH') where state != 'TX' NULL value references can never use indexes where state IS NULL where state IS NOT NULL expression references can never use indexes where substr(city,1,3) = 'DAL' where city like 'DAL%' where city || state = 'DALLASTX' where city = 'DALLAS' and state = 'TX where salary * 12 >= 24000 where salary >= 2000

[Index Not used] [Index Used] [Index Used] [Index Not used] [Index Not used] [Index Not used] [Index Not used] [Index Not used] [Index Used] [Index Not used] [Index Used] [Index Not used] [Index Used]

Rule #2:Watch Non-Indexed WHERE Conditions


Oracle evaluates Non-Indexed conditions linked by AND bottom up Bad: select * from address where areacode = 972 and type_nr = (select seq_nr from code_table where type = HOME) Good: select * from address where type_nr = (select seq_nr from code_table where type = HOME) and areacode = 972 Oracle evaluates Non-Indexed conditions linked by OR top down Bad: select * from address where type_nr = (select seq_nr from code_table where type = HOME) or areacode = 972 Good: select * from address where areacode = 972 or type_nr = (select seq_nr from code_table where type = HOME)

Rule #3:Order Table in the FROM Clause

important under rule based optimizer, and won't hurt under cost based optimizer
order FROM clauses in descending order of table sizes based upon row counts for example select * from larger table, smaller table select * from larger table, smaller table, smallest table select * from larger table, smaller table, associative table

Note rule based optimizer only

Rule #4:Consider IN or UNION in place of OR


if columns are not indexed, stick with OR if columns are indexed, use IN or UNION in place of OR IN example Bad: select * from address where state = 'TX or state = 'FL or state = 'OH Good: select * from address where state in ('TX','FL','OH') UNION example Bad: select * from address where state = TX or areacode = 972 Good: select * from address where state = TX union select * from address where areacode = 972

Rule #5:Weigh JOIN versus EXISTS Sub-Query


use table JOIN instead of EXISTS sub-query when the percentage of rows returned from the outer sub-query is high select e.name, e.phone, e.mailstop from employee e, department d where e.deptno = d.deptno and d.status = ACTIVE use EXISTS sub-query instead of table JOIN when the percentage of rows returned from the outer sub-query is low select e.name, e.phone, e.mailstop from employee e where e.deptno in (select d.deptno from department d where d.status != ACTIVE)

Rule #6:Consider EXISTS in place of DISTINCT

avoid joins that use DISTINCT, use EXISTS sub-query instead

Bad: select distinct deptno, deptname from emp, dept where emp.deptno = dept.deptno

Good: select deptno, deptname from dept where exists (select X from emp where emp.deptno = dept.deptno)

Note only has to find one match

Rule #7: Which one is better IN vs SubQuery


SELECT EMPLOYEE_ID, FIRST_NAME, E.LAST_NAME, E.SALARY FROM EMPLOYEES E WHERE EXISTS (SELECT 1 FROM ORDERS O WHERE E.EMPLOYEE_ID = O.SALES_REP_ID AND O.CUSTOMER_ID = 144)

SELECT E.EMPLOYEE_ID , E.FIRST_NAME , E.LAST_NAME , E.SALARY FROM EMPLOYEES E WHERE E.EMPLOYEE_ID IN (SELECT O.SALES_REP_ID FROM ORDERS O WHERE O.CUSTOMER_ID = 144)
26

Rule #8:Consider NOT EXISTS in place of NOT IN

avoid sub-queries that use NOT IN, use NOT EXISTS instead Bad: select * from emp where deptno not in (select deptno from dept where deptstatus = A) Good: select * from emp where not exists (select X from dept where deptstatus = A and dept.deptno = emp.deptno)

Note only has to find one non-match

Rule #9:COUNT Using Indexed Column or Asterisk

when counting rows, use COUNT on indexed column or asterisk select count(indexed_column) from table select count(*) from table Select count(non_indexed_column) from table select count(1) from table

[Most Efficient]

Note rule based optimizer only

Rule #10:Ordering Via the WHERE Clause

a dummy WHERE clause referencing an indexed column will retrieve all records in ascending order (descending for 8i descending index)

not perform a costly sort operation


Bad: select * from address order by city Good: select * from address where city >

Rule #11: Avoid including a HAVING clause in SELECT statements

SELECT region, AVG (loc_size) FROM location GROUP BY region HAVING region != 'SYDNEY' AND region != 'PERTH'; SELECT region, AVG (loc_size) FROM location WHERE region != 'SYDNEY' AND region != 'PERTH'; GROUP BY region;

Rule #12: Minimize number to Table lookups SELECT emp_name FROM emp WHERE emp_cat = (SELECT MAX (category) FROM emp_categories) AND emp_range = (SELECT MAX (sal_range) FROM emp_categories) AND emp_dept = 0020; SELECT emp_name FROM emp WHERE (emp_cat, sal_range) = (SELECT MAX (category), MAX (sal_range)

FROM emp_categories) AND emp_dept = 0020;

31

Rule #13: Add all possible Joins


Make sure everything that can be joined is joined (for 3 or more tables)

Instead of:
SELECT * FROM t1, t2, t3 WHERE t1.emp_id = t2.emp_id AND t2.emp_id = t3.emp_id

add:
SELECT * FROM t1, t2, t3 WHERE t1.emp_id = t2.emp_id AND t2.emp_id = t3.emp_id AND t1.emp_id = t3.temp_id;

Rule #14: AddHints /*+ TUNE*/

Compiler directive- impacts optimizers behavior, not query result

Hints force the optimizer approach and goal.


Hints may not always be Used

Syntax must be accurate - if not, hint is ignored If aliasing tables, must use alias in hint

Do not specify schema names in the hint even if they are specified in the FROM clause

33

Mostly Used Ones


Hints for Optimization Approaches and Goals Hints for Access Paths
/*+ ALL_ROWS */ /*+ FIRST_ROWS */ /*+ CHOOSE */ /*+ RULE */

/*+ FULL(table) */ /*+ INDEX(table index) */ Hints for Join Orders ORDERED

Hints for Join Operations CACHE


DRIVING_SITE

34

Rule #15:Use PL/SQL to reduce network traffic


Utilize PL/SQL to group related SQL commands and thereby reduce network traffic Bad: select city_name, state_code into :v_city, :v_sate from zip_codes where zip_code = 75022; insert into customer (Bert Scalzo,75022, :v_city, v_state); Good: begin select city_name, state_code into :v_city, :v_sate from zip_codes where zip_code = 75022; insert into customer (Bert Scalzo,75022, :v_city, v_state); end; /

Golden Rule #5: Know your data, Know what youre doing,Test and find the best way

PL\SQL Codes Must Watch

Rule #1:Use proper size of Variables defined.

V_NAME VARCHAR2(2000); V_AGE NUMBER(1000); V_ADD NVARCHAR2(4000);

V_NAME EMPLOYEE.NAME%TYPE; V_AGE NUMBER(3); V_ADD EMPLOYEE.ADDRESS%TYPE;

Rule #2 : Passing Large Data Structures with NOCOPY

The PL/SQL runtime engine has two different methods for passing parameter values between stored procedures and functions, by value and by reference.

procedure get_customer_orders ( p_customer_id in number, p_orders out nocopy orders_coll ); theorders orders_coll; get_customer_orders(124, theorders);

Rule #3 : Use Temporary Tables

If the amount of data to be processed or utilized from your PL/SQL procedure is too large to fit comfortably in a PL/SQL table, use a GLOBAL TEMPORARY table rather than a normal table. A GLOBAL TEMPORARY table has a persistent definition but data is not persistent and the global temporary table generates no redo or rollback information. For example if you are processing a large number of rows, the results of which are not needed when the current session has ended, you should create the table as a temporary table instead: create global temporary table results_temp (...) on commit preserve rows; The on commit preserve rows clause tells the SQL engine that when a transaction is committed the table should not be cleared. The global temporary table will be created in the users temporary tablespace when the procedure populates it with data and the DIRECT_IO_COUNT will be used to govern the IO throughput (this usually defaults to 64 blocks).

Rule #3 : Reduce Network Traffic With use of bulk collect

The bulk operation takes less than half the time to populate the collection from the query.

BULK COLLECT INTO record;


BULK COLLECT INTO record LIMIT V_NUM;

Rule #4 : Use FORALL for DML Operations


EXECUTE IMMEDIATE TRUNCATE TABLE forall_test; FOR i IN l_tab.first .. l_tab.last LOOP INSERT INTO forall_test (id, code, description) VALUES (l_tab(i).id, l_tab(i).code, l_tab(i).description); END LOOP;

EXECUTE IMMEDIATE TRUNCATE TABLE forall_test;


FORALL i IN l_tab.first .. l_tab.last INSERT INTO forall_test VALUES l_tab(i);

Rule #5 : Use RETURNING Clause in FORALL Operations

FOR i IN l_id_tab.first .. l_id_tab.last LOOP UPDATE forall_test SET id = l_id_tab(i), code = l_code_tab(i), description = l_desc_tab(i) WHERE id = l_id_tab(i); END LOOP; FORALL i IN l_id_tab.first .. l_id_tab.last UPDATE forall_test SET id = l_id_tab(i), code = l_code_tab(i), description = l_desc_tab(i) WHERE id = l_id_tab(i) RETURNING id, description BULK COLLECT INTO l_out_tab;

Rule #6 : Tuning Dynamic SQL with EXECUTE IMMEDIATE and Cursor Variables

DECLARE TYPE EmpCurTyp IS REF CURSOR; emp_cv EmpCurTyp;

v_ename VARCHAR2(15);
v_sal NUMBER := 1000; table_name VARCHAR2(30) := 'employees'; BEGIN

OPEN emp_cv FOR 'SELECT last_name, salary FROM ' || table_name || ' WHERE salary > :s' USING v_sal;
CLOSE emp_cv; END; /

Any Questions ?

Thanks for your time

Vous aimerez peut-être aussi