WHERE Clause Try to avoid operations on database objects referenced in the WHERE clause.
| Given Query | Alternative | SELECT ename, hiredate, sal FROM emp WHERE SUBSTR(ename,1,3) = 'SCO'; | SELECT ename, hiredate, sal FROM emp WHERE ename LIKE 'SCO%'; | | VARIABLE name VARCHAR2(20) exec name := 'SCOTT'
SELECT ename, hiredate, sal FROM emp WHERE ename = NVL (:name, ename); | VARIABLE name VARCHAR2(20) exec name := 'SCOTT'
SELECT ename, hiredate, sal FROM emp WHERE ename LIKE NVL (:name, '%'); | | SELECT ename, hiredate, sal FROM emp WHERE TRUNC (hiredate) = TRUNC (SYSDATE); | SELECT ename, hiredate, sal FROM emp WHERE hiredate BETWEEN TRUNC (SYSDATE) AND TRUNC (SYSDATE) + .99999; | SELECT ename, hiredate, sal FROM emp WHERE ename || empno = 'SCOTT7788'; | SELECT ename, hiredate, sal FROM emp WHERE ename = 'SCOTT AND empno = 7788; | SELECT ename, hiredate, sal FROM emp WHERE sal + 3000 < 5000; | SELECT ename, hiredate, sal FROM emp WHERE sal < 2000; | | SELECT ename, hiredate, sal FROM emp WHERE sal != 0; | SELECT ename, hiredate, sal FROM emp WHERE sal > 0; | HAVING ClauseThe HAVING clause filters selected rows only after all rows have been fetched. Using a WHERE clause helps reduce overheads in sorting, summing, etc. HAVING clauses should only be used when columns with summary operations applied to them are restricted by the clause.
| Given Query | Alternative | | SELECT d.dname, AVG (e.sal) FROM emp e, dept d WHERE e.deptno = d.deptno GROUP BY d.dname HAVING dname != 'RESEAECH' AND dname != 'SALES'; | SELECT d.dname, AVG (e.sal) FROM emp e, dept d WHERE e.deptno = d.deptno AND dname != 'RESEAECH' AND dname != 'SALES' GROUP BY d.dname; | Combined Subqueries Minimize the number of table lookups (subquery blocks) in queries, particularly if your statements include subquery SELECTs or multicolumn UPDATEs.
| Separate Subqueries | Combined Subqueries | SELECT ename FROM emp WHERE sal = (SELECT MAX (sal) FROM lookup) AND comm = (SELECT MAX (comm) FROM lookup); | SELECT ename FROM emp WHERE (sal,comm) = (SELECT MAX (sal), MAX(comm) FROM lookup); |
EXISTS, NOT IN, Table Joins Consider the alternatives EXISTS, IN and table joins when doing multiple table joins. None of these are consistently faster; it depends on your data. | SELECT ename FROM emp E WHERE EXISTS (SELECT 'X' FROM dept WHERE deptno = E.deptno AND dname = 'ACCOUNTING'); | SELECT ename FROM emp E WHERE deptno IN (SELECT deptno FROM dept WHERE deptno = E.deptno AND dname = 'ACCOUNTING'); | SELECT ename FROM dept D, emp E WHERE E.deptno = D.deptno AND D.dname = 'ACCOUNTING'; |
DISTINCTAvoid 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-to-many relationship. The DISTINCT operator causes Oracle to fetch all rows satisfying the table join and then sort and filter out duplicate values. EXISTS is a faster alternative, because the Oracle optimizer realizes when the subquery has been satisfied once, there is no need to proceed further and the next matching row can be fetched. | Given Query | Alternative | | SELECT DISTINCT d.deptno, d.dname FROM dept D, emp E WHERE D.deptno = E.deptno; | SELECT d.deptno, d.dname FROM dept D WHERE EXISTS (SELECT 'X' FROM emp E WHERE E.deptno = D.deptno); |
UNION ALLConsider whether a UNION ALL will suffice in place of a UNION. 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. A UNION ALL simply returns all rows including duplicates and does not have to perform any sort, merge or filter. If your tables are mutually exclusive (include no duplicate records), or you don't care if duplicates are returned, the UNION ALL is much more efficient. | UNION | UNION ALL | | SELECT acct, balance FROM debit WHERE trandate = '31-DEC-95' UNION SELECT acct, balance FROM credit WHERE trandate = '31-DEC-95'; | SELECT acct, balance FROM debit WHERE trandate = '31-DEC-95' UNION ALL SELECT acct, balance FROM credit WHERE trandate = '31-DEC-95'; | DECODE Consider using DECODE to avoid having to scan the same rows repetitively or join the same table repetitively. Note, DECODE is not necessarily faster as it depends on your data and the complexity of the resulting query. Also, using DECODE requires you to change your code when new values are allowed in the field. | SELECT COUNT(*) FROM emp WHERE status = 'Y' AND ename LIKE 'SMITH%'; ---------- SELECT COUNT(*) FROM emp WHERE status = 'N' AND ename LIKE 'SMITH%'; | | SELECT COUNT(DECODE(status, 'Y', 'X', NULL)) Y_count, COUNT(DECODE(status, 'N', 'X', NULL)) N_count FROM emp WHERE ename LIKE 'SMITH%'; |
Anti Joins An anti-join is used to return rows from a table that that are present in another table. It might be used for example between DEPT and EMP to return only those rows in DEPT that didn't join to anything in EMP; | SELECT * FROM dept WHERE deptno NOT IN (SELECT deptno FROM EMP); | | SELECT dept.* FROM dept, emp WHERE dept.deptno = emp.deptno (+) AND emp.ROWID IS NULL; | SELECT * FROM dept WHERE NOT EXISTS (SELECT NULL FROM emp WHERE emp.deptno = dept.deptno); |
Full Outer JoinsNormally, an outer join of table A to table B would return every record in table A, and if it had a mate in table B, that would be returned as well. Every row in table A would be output, but some rows of table B might not appear in the result set. A full outer join would return ebery row in table A, as well as every row in table B. The syntax for a full outer join is new in Oracle 9i, but it is a syntactic convenience, it is possible to produce full outer joins sets using conventional SQL. update emp set deptno = 9 where deptno = 10; commit; | Conventional SQL | New Syntax | SELECT empno, ename, dept.deptno, dname FROM emp, dept WHERE emp.deptno(+) = dept.deptno UNION ALL SELECT empno, ename, emp.deptno, NULL FROM emp, dept WHERE emp.deptno = dept.deptno(+) AND dept.deptno IS NULL ORDER BY 1,2,3,4; EMPNO ENAME DEPTNO DNAME ---------- ---------- ---------- -------------- 7369 SMITH 20 RESEARCH 7499 ALLEN 30 SALES 7521 WARD 30 SALES 7566 JONES 20 RESEARCH 7654 MARTIN 30 SALES 7698 BLAKE 30 SALES 7782 CLARK 9 7788 SCOTT 20 RESEARCH 7839 KING 9 7844 TURNER 30 SALES 7876 ADAMS 20 RESEARCH 7900 JAMES 30 SALES 7902 FORD 20 RESEARCH 7934 MILLER 9 10 ACCOUNTING 40 OPERATIONS | SELECT empno, ename, NVL(dept.deptno,emp.deptno) deptno, dname FROM emp FULL OUTER JOIN dept ON (emp.deptno = dept.deptno) ORDER BY 1,2,3,4;
EMPNO ENAME DEPTNO DNAME ---------- ---------- ---------- -------------- 7369 SMITH 20 RESEARCH 7499 ALLEN 30 SALES 7521 WARD 30 SALES 7566 JONES 20 RESEARCH 7654 MARTIN 30 SALES 7698 BLAKE 30 SALES 7782 CLARK 9 7788 SCOTT 20 RESEARCH 7839 KING 9 7844 TURNER 30 SALES 7876 ADAMS 20 RESEARCH 7900 JAMES 30 SALES 7902 FORD 20 RESEARCH 7934 MILLER 9 10 ACCOUNTING 40 OPERATIONS |
|