SQL Tuning Tips SQL is the heart of the Oracle system.

You can use many different SQL statements to achieve the same result. It is often the case that only one statement will be the most efficient choice in a given situation. The tips below include information about whether one form of the statement is always MORE efficient or whether each statement is an alternative and the efficency will vary depending on your application. Oracle processes SQL in two steps: parsing and execution. Tuning may speed up your SQL by reducing either parsing, execution or both. Note, tuning SQL should only be done after your code is working correctly. Be aware that there is an inevitable tug-of-war between writing efficient SQL and understandable SQL. TIP 1 (Best Tip): SQL cannot be shared within Oracle unless it is absolutely identical. Statements must have match exactly in case, white space and underlying schema objects to be shared within Oracle's memory. Oracle avoids the parsing step for each subsequent use of an identical statement.

sql> SELECT NAME FROM S_CUSTOMER WHERE ID = 212; sql> SELECT NAME FROM s_customer WHERE ID = 212; sql> SELECT NAME FROM S_CUSTOMER WHERE ID=212; sql> SELECT NAME FROM S_CUSTOMER WHERE ID=212;

statement to match lower case white space

white space

o

Use SQL standards within an application. Rules like the following are easy to implement and will allow MORE sharing within Oracle's memory. Using a single case for all SQL verbs Beginning all SQL verbs on a new line Right or left aligning verbs within the initial SQL verb Separating all words with a single space

1

then the SQL is different and will not be shared.o Use bind variables. This reduces parse time AND prevents future syntax errors if someone adds a column to one of the tables with the same name as a column in another table.1. The values of bind variables do not need to be the same for two statements to be considered identical. If two identical SQL statements vary because an identical table has two different aliases. (ORA-00918: COLUMN AMBIGUOUSLY DEFINED) TIP 2: Beware of WHERE clauses which do not use indexes at all. Sharable SQL SELECT * FROM emp WHERE emp_no = :B1. 2 . All of these WHERE clauses can be rewritten to use an index while returning the same values. amount FROM transaction WHERE account_name LIKE 'CAPITAL%'. Do Not Use SELECT account_name. Bind value: 123 Bind value: 987 Non-sharable SQL SELECT * FROM emp WHERE emp_no = 123. Even if there is an index over a column that is referenced by a WHERE clause included in this section. Bind variables are not substituted until a statement has been successfully parsed. SELECT * FROM emp WHERE emp_no = :B1. trans_date. trans_date. In other words. SELECT * FROM emp WHERE emp_no = 987.7) = 'CAPITAL'. Use SELECT account_name. amount FROM transaction WHERE SUBSTR(account_name. Oracle will ignore the index. don't perform operations on database objects referenced in the WHERE clause. o Use a standard approach to table aliases. o Use table aliases and prefix all column names by their aliases when MORE than one table is involved in a query.

amount FROM transaction WHERE amount > 0. amount FROM transaction WHERE amount > 0. trans_date. amount FROM transaction WHERE amount < 2000. trans_date.99999. TIP 4: Avoid including a HAVING clause in SELECT statements. trans_date. trans_date. amount FROM transaction WHERE trans_date BETWEEN TRUNC (SYSDATE) AND TRUNC (SYSDATE) + . amount FROM transaction WHERE account_name = NVL ( :acc_name. amount FROM transaction WHERE account_name = 'AMEX' AND account_type = 'A'. trans_date. amount FROM transaction WHERE amount + 3000 < 5000. SELECT account_name. trans_date. summing. SELECT account_name. account_name). Views are SELECT statements and can be tuned in just the same way as any other type of SELECT statement can be. SELECT account_name. TIP 3: Don't forget to tune views. SELECT account_name. amount FROM transaction WHERE account_name LIKE NVL ( :acc_name. trans_date. trans_date. SELECT account_name. All tuning applicable to any SQL statement are equally applicable to views. '%'). trans_date. etc. SELECT account_name. amount FROM transaction WHERE account_name || account_type = 'AMEXA'. amount FROM transaction WHERE amount != 0. SELECT account_name. Do Not Use Use 3 . trans_date. SELECT account_name. SELECT account_name.SELECT account_name. trans_date. Using a WHERE clause helps reduce overheads in sorting. trans_date. SELECT account_name. The HAVING clause filters selected rows only after all rows have been fetched. amount FROM transaction WHERE TRUNC (trans_date) = TRUNC (SYSDATE). SELECT account_name. amount FROM transaction WHERE amount NOT = 0. HAVING clauses should only be used when columns with summary operations applied to them are restricted by the clause.

it depends on your data. None of these are consistently faster. SELECT region. If there is a poor performer here. (Note. this query returns the employee names from each department in department category 'A'. it's likely the IN clause.SELECT region. TIP 5: Minimize the number of table lookups (subquery blocks) in queries. SELECT emp_name FROM emp E WHERE dept_no IN ( SELECT dept_no FROM dept WHERE dept_no = E. MAX (sal_range) FROM emp_categories) AND emp_dept = 0020. sal_range) = (SELECT MAX (category).dept_no AND dept_cat = 'A').dept_no 4 . AVG (loc_size) FROM location GROUP BY region HAVING region != 'SYDNEY' AND region != 'PERTH'. IN and table joins when doing multiple table joins.) SELECT emp_name FROM emp E WHERE EXISTS ( SELECT 'X' FROM dept WHERE dept_no = E. particularly if your statements include subquery SELECTs or multicolumn UPDATEs. AVG (loc_size) FROM location WHERE region != 'SYDNEY' AND region != 'PERTH'. SELECT emp_name FROM emp WHERE (emp_cat. Separate Subqueries 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. GROUP BY region. Combined Subqueries TIP 6: Consider the alternatives EXISTS.

EXISTS is a faster alternative. merge or filter. The DISTINCT operator causes Oracle to fetch all rows satisfying the table join and then sort and filter out duplicate values.dept_no AND D. there is no need to proceed further and the next matching row can be fetched. because the Oracle optimizer realizes when the subquery has been satisfied once. If your tables are mutually exclusive (include no duplicate records). emp E WHERE D.dept_no). balance_amt FROM credit_transactions WHERE tran_date = '31-DEC-95'.dept_no = E.dept_cat = 'A'.) Do Not Use SELECT DISTINCT dept_no. The UNION clause forces all rows returned by each portion of the UNION to be sorted and merged and duplicates to be filtered before the first row is returned. the UNION ALL is much MORE efficient. SELECT emp_name FROM dept D. balance_amt FROM debit_transactions WHERE tran_date = '31-DEC-95' UNION SELECT acct_num. dept_name FROM dept D. A UNION ALL simply returns all rows including duplicates and does not have to perform any sort. (Note: This query returns all department numbers and names which have at least one employee.dept_no = D. UNION SELECT acct_num. TIP 8: Consider whether a UNION ALL will suffice in place of a UNION.dept_no. balance_amt FROM debit_transactions WHERE tran_date = '31-DEC-95' UNION ALL SELECT acct_num. emp E WHERE E.dept_no = D. 5 .AND dept_cat = 'A'). UNION ALL SELECT acct_num. dept_name FROM dept D WHERE EXISTS ( SELECT 'X' FROM emp E WHERE E. balance_amt FROM credit_transactions WHERE tran_date = '31-DEC-95'. TIP 7: Avoid joins that require the DISTINCT qualifier on the SELECT list in queries which are used to determine information at the owner end of a one-tomany relationship. Use SELECT dept_no. or you don't care if duplicates are returned.

if the type is supported in the programming language you are using. FROM emp WHERE emp_no = TO_NUMBER('123'). ---------SELECT COUNT(*) FROM emp WHERE status = 'N' AND emp_name LIKE 'SMITH%'.. 'X'.TIP 9: Consider using DECODE to avoid having to scan the same rows repetitively or join the same table repetitively. COUNT(DECODE(status. NULL)) N_count FROM emp WHERE emp_name LIKE 'SMITH%'.. Datatype of field in where clause emp_no indexed numeric emp_type indexed varchar2 Your Query After Implicit Conversion Index Used? SELECT . FROM emp WHERE emp_no = '123'. Note. Depending on the type of conversion. Make sure you declare your program variables as the same type as your Oracle columns. FROM emp WHERE emp_type = 123. SELECT .. indexes may not be used. 6 . FROM emp NO! WHERE TO_NUMBER (emp_type) = 123. SELECT . TIP 10: Oracle automatically performs simple column type conversions (or casting) when it compares columns of different types. Also. SELECT COUNT(*) FROM emp WHERE status = 'Y' AND emp_name LIKE 'SMITH%'. DECODE is not necessarily faster as it depends on your data and the complexity of the resulting query. 'Y'.. using DECODE requires you to change your code when new values are allowed in the field. SELECT COUNT(DECODE(status... NULL)) Y_count.. 'X'. 'N'.. YES SELECT .

7 .

Sign up to vote on this title
UsefulNot useful