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 SQL’s written Do your developers know: •Sub-queries (correlated and not) •Outer Joins •Minus •Union and Union-All

Golden Rule #1: It’s the application stupid!

and after you‟re done it may be too late. When Issue is reported. and after! . and then identify problem areas for improvement. Often it‟s best to apply general tuning guidelines as you go. Golden Rule #2: Best to tune before.When Can One start tuning?    When I write a Code. As and When Required. Tuning as you go may be impractical. during.

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?  .

this leads to few I/O's.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. .

function-based indexes. reverse key indexes and text indexes are all just variations on the two main types What B-Stands in B-Tree? .Various Types Of Indexes B-Tree indexes  Bitmap indexes  Cluster indexes. bitmap join indexes.

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 kind of index one need to create?  .  How to find which columns need to be indexed.What to Index and What Not? Should I Index each and every column.

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 .Are they really good? Well the answer of this is bit trick.

Time To Watch your SQL Now Rule #1: Watch Indexed WHERE Conditions Assume index on address (city.1. '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. != and <> disable index use •where state not in ('TX'. state) •non-leading index column references cannot use indexes •where state = 'TX' •where city = 'DALLAS' •where state = 'TX' and city = 'DALLAS' •NOT.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‟) .

smaller table •select * from larger table. smaller table.Rule #3:Order Table in the FROM Clause •important under rule based optimizer. associative table Note – rule based optimizer only . smaller table. smallest table •select * from larger table. 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.

'FL'. stick with OR •if columns are indexed.Rule #4:Consider IN or UNION in place of OR •if columns are not indexed.'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 . 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'.

phone. e. e.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.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.mailstop from employee e where e.deptno from department d where d.phone.name.name.deptno = d.deptno in (select d.mailstop from employee e. e.status != „ACTIVE‟) . e. department d where e.deptno and d.

dept where emp.deptno •Good: select deptno. use EXISTS sub-query instead •Bad: select distinct deptno.deptno = dept.Rule #6:Consider EXISTS in place of DISTINCT •avoid joins that use DISTINCT. deptname from emp.deptno = dept. deptname from dept where exists (select „X‟ from emp where emp.deptno) Note – only has to find one match .

SALARY FROM EMPLOYEES E WHERE E.SALES_REP_ID FROM ORDERS O WHERE O. E.SALARY FROM EMPLOYEES E WHERE EXISTS (SELECT 1 FROM ORDERS O WHERE E. E.Rule #7: Which one is better IN vs SubQuery SELECT EMPLOYEE_ID.EMPLOYEE_ID = O.LAST_NAME.CUSTOMER_ID = 144) 26 .LAST_NAME .SALES_REP_ID AND O.CUSTOMER_ID = 144) SELECT E.EMPLOYEE_ID IN (SELECT O. E. E.EMPLOYEE_ID . E. FIRST_NAME.FIRST_NAME .

deptno = emp. 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.Rule #8:Consider NOT EXISTS in place of NOT IN •avoid sub-queries that use NOT IN.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 > „‟ .

GROUP BY region. SELECT region. AVG (loc_size) FROM location WHERE region != 'SYDNEY' AND region != 'PERTH'.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'.

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. sal_range) = (SELECT MAX (category). 31 . MAX (sal_range) FROM emp_categories) AND emp_dept = 0020. SELECT emp_name FROM emp WHERE (emp_cat.

emp_id AND t2.emp_id = t2.emp_id = t3. t2.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. t3 WHERE t1.emp_id = t3. t2.emp_id add: SELECT * FROM t1.emp_id = t2.emp_id AND t1.emp_id AND t2. 3 . t3 WHERE t1.temp_id.emp_id = t3.

if not.impacts optimizer‟s behavior.Rule #14: AddHints /*+ TUNE*/ ◦ Compiler directive. not query result ◦ Hints force the optimizer approach and goal. must use alias in hint – Do not specify schema names in the hint even if they are specified in the FROM clause 33 . ◦ Hints may not always be Used – – Syntax must be accurate . hint is ignored If aliasing tables.

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 .

:v_sate from zip_codes where zip_code = „75022‟. Know what you’re doing. insert into customer („Bert Scalzo‟.‟75022‟. insert into customer („Bert Scalzo‟. v_state). :v_city. state_code into :v_city.‟75022‟. end.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. / Golden Rule #5: Know your data. state_code into :v_city. :v_sate from zip_codes where zip_code = „75022‟. :v_city. v_state).Test and find the best way . •Good: begin select city_name.

PL\SQL Codes Must Watch .

V_NAME VARCHAR2(2000). V_NAME EMPLOYEE.Rule #1:Use proper size of Variables defined.NAME%TYPE. . V_ADD EMPLOYEE. V_AGE NUMBER(1000). V_AGE NUMBER(3).ADDRESS%TYPE. V_ADD NVARCHAR2(4000).

theorders orders_coll. by value and by reference.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. procedure get_customer_orders ( p_customer_id in number. p_orders out nocopy orders_coll ). get_customer_orders(124. . theorders).

you should create the table as a temporary table instead: create global temporary table results_temp (. the results of which are not needed when the current session has ended..) on commit preserve rows. For example if you are processing a large number of rows.. A GLOBAL TEMPORARY table has a persistent definition but data is not persistent and the global temporary table generates no redo or rollback information. 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). The “on commit preserve rows” clause tells the SQL engine that when a transaction is committed the table should not be cleared. use a GLOBAL TEMPORARY table rather than a normal table.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.   .

  BULK COLLECT INTO record. BULK COLLECT INTO record LIMIT V_NUM. .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.

code. description) VALUES (l_tab(i). .first .Rule #4 : Use FORALL for DML Operations EXECUTE IMMEDIATE „TRUNCATE TABLE forall_test‟. l_tab. EXECUTE IMMEDIATE „TRUNCATE TABLE forall_test‟. l_tab(i).code. l_tab(i).last LOOP INSERT INTO forall_test (id.. FOR i IN l_tab.id. FORALL i IN l_tab.description)..last INSERT INTO forall_test VALUES l_tab(i). END LOOP. l_tab.first .

last LOOP UPDATE forall_test SET id = l_id_tab(i).Rule #5 : Use RETURNING Clause in FORALL Operations FOR i IN l_id_tab. code = l_code_tab(i)..last UPDATE forall_test SET id = l_id_tab(i). description = l_desc_tab(i) WHERE id = l_id_tab(i). . END LOOP.first . code = l_code_tab(i). l_id_tab.. l_id_tab. description BULK COLLECT INTO l_out_tab. description = l_desc_tab(i) WHERE id = l_id_tab(i) RETURNING id.first . FORALL i IN l_id_tab.

END. salary FROM ' || table_name || ' WHERE salary > :s' USING v_sal. v_ename VARCHAR2(15).Rule #6 : Tuning Dynamic SQL with EXECUTE IMMEDIATE and Cursor Variables DECLARE TYPE EmpCurTyp IS REF CURSOR. table_name VARCHAR2(30) := 'employees'. v_sal NUMBER := 1000. / . BEGIN OPEN emp_cv FOR 'SELECT last_name. emp_cv EmpCurTyp. CLOSE emp_cv.

Any Questions ? Thanks for your time .

Sign up to vote on this title
UsefulNot useful