Oracle 8i or 9i
RBO(rule-based optimizer)
CBO
1)2张行数不一致的表连接
表TAB1行数:16,384行
表TAB2行数:1行
×SELECT COUNT(*) FROM TAB2, TAB1;
○SELECT COUNT(*) FROM TAB1, TAB2;
2)3张表连接
×SELECT *
FROM EMP E,
LOC L,
CAT C
WHERE E.emp_no BETWEEN 1000 AND 2000
AND E.cat_no = C.cat_no
AND E.locn = L.locn;
○SELECT *
FROM LOC L,
CAT C,
EMP E
WHERE E.emp_no BETWEEN 1000 AND 2000
AND E.cat_no = C.cat_no
AND E.locn = L.locn;
1) 使用索引引起的where语句效率
使用AND语句时行数多的放在前面
×SELECT *
FROM emp E
WHERE emp_sal > 50000
AND emp_type = 'MANAGER'
AND 25 < (SELECT COUNT(*) FROM EMP WHERE emp_mgr = E.emp_no);
○SELECT *
FROM emp E
WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE
emp_mgr = E.emp_no)
AND emp_sal > 50000
AND emp_type = 'MANAGER';
使用OR语句时,行数多的放在后面
×SELECT *
FROM emp E
WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE emp_mgr = E.emp_no)
OR (emp_sal > 50000
AND emp_type = 'MANAGER');
○SELECT *
FROM emp E
WHERE (emp_sal > 50000
AND emp_type = 'MANAGER')
OR 25 < (SELECT COUNT(*) FROM EMP WHERE emp_mgr = E.emp_no);
2)ROWID的使用
使用ROWID的WHERE语句效率最高。
SELECT ROWID, ...
INTO :emp_rowid, ...
FROM emp
WHERE emp.emp_no = 56722
FOR UPDATE;
UPDATE emp
SET emp.name = ... ,
WHERE ROWID = :emp_rowid;
3)减少访问次数
×SELECT emp_name, sal, grade
FROM emp
WHERE emp_no = 0342;
SELECT emp_name, sal, grade
FROM emp
WHERE emp_no = 0291;
○SELECT A.emp_name, A.sal, A.grade,
B.emp_name, B.sal, B.grade
FROM emp A, emp B
WHERE A.emp_no = 0342
4)Where语句的索引的使用
(1)SUBSTR
×SELECT acc_name, trans_date, amount
FROM transaction
WHERE SUBSTR(account_name,1,7) = 'CAPITAL';
○SELECT acc_name, trans_date, amount
FROM transaction
WHERE account_name LIKE 'CAPITAL%';
(2)!=
×SELECT acc_name, trans_date, amount
FROM transaction
WHERE amount != 0;
○SELECT acc_name, trans_date, amount
FROM transaction
WHERE amount > 0;
(3)TRUNC
×SELECT acc_name, trans_date, amount
FROM transaction
WHERE TRUNC(trans_date) = TRUNC(SYSDATE);
○SELECT acc_name, trans_date, amount
FROM transaction
WHERE trans_date
BETWEEN TRUNC(SYSDATE)
AND TRUNC(SYSDATE) + .99999;
(4)||
×SELECT acc_name, trans_date, amount
FROM transaction
WHERE acc_name || acc_type = 'AMEXA';
○SELECT acc_name, trans_date, amount
FROM transaction
WHERE acc_name = 'AMEX'
AND acc_type = 'A';
(5)运算
×SELECT acc_name, trans_date, amount
FROM transaction
WHERE amount + 3000 < 5000;
○SELECT acc_name, trans_date, amount
FROM transaction
WHERE amount < 5000 - 3000;
×SELECT COUNT(*), SUM(salary)
FROM emp
WHERE dept_no = 0020
AND emp_name LIKE 'SMITH%';
SELECT COUNT(*), SUM(salary)
FROM emp
WHERE dept_no = 0030
AND emp_name LIKE 'SMITH%';
○SELECT COUNT(DECODE(dept_no, 0020, 'X', NULL)) D0020_count,
COUNT (DECODE(dept_no, 0030, 'X', NULL)) D0030_count,
SUM (DECODE(dept, 0020, salary, NULL)) D0020_sal,
SUM (DECODE(dept, 0030, salary, NULL)) D0030_sal
FROM emp
WHERE emp_name LIKE 'SMITH%';
×SELECT E.emp_no, name, tax_no, C.comp_code, comp_name
FROM company C, emp E
WHERE E.comp_code = C.comp_code;
○SELECT E.emp_no, E.name, E.tax_no, C.comp_code, C.comp_name
FROM company C, emp E
WHERE E.comp_code = C.comp_code;
DELETE FROM emp E
WHERE E.rowid > ( SELECT MIN(X.rowid)
FROM emp X
WHERE X.emp_no = E.emp_no );
SELECT COUNT(有索引的列) FROM TRANS;
SELECT COUNT(*) FROM TRANS;
SELECT COUNT(1) FROM TRANS;
×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
×SELECT emp_name
FROM emp
WHERE (emp_cat, sal_range) =
(SELECT MAX(category), MAX(sal_range) FROM emp_categories)
AND emp_dept = 0020;
○SELECT emp_name
FROM emp
WHERE emp_cat = (SELECT MAX(category) FROM emp_categories)
AND sal_range = (SELECT MAX(sal_range) FROM emp_categories)
AND emp_dept = 0020;
×SELECT ...
FROM dept D, emp E
WHERE E.dept_no = D.dept_no
AND E.emp_type = 'MANAGER'
AND D.dept_cat = 'A';
○SELECT ...
FROM emp E
WHERE EXISTS ( SELECT 'X'FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = 'A')
AND E.emp_type = 'MANAGER';
×SELECT ...
FROM dept D, emp E
WHERE E.dept_no = D.dept_no
AND (E.emp_type = 'MANAGER'
OR D.dept_cat = 'A');
○SELECT ...
FROM emp E
WHERE E.emp_type = 'MANAGER';
OR EXISTS ( SELECT 'X'
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = 'A');
×SELECT DISTINCT dept_no, dept_name
FROM dept D, emp E
WHERE D.dept_no = E.dept_no;
○SELECT dept_no, dept_name
FROM dept D
WHERE EXISTS ( SELECT 'X'
FROM emp E
WHERE E.dept_no = D.dept_no);
×SELECT ...
FROM emp
WHERE dept_no NOT IN ( SELECT dept_no
FROM dept
WHERE dept_cat = 'A');
○SELECT ...
FROM emp E
WHERE NOT EXISTS ( SELECT 'X'
FROM dept
WHERE dept_no = E.dept_no
AND dept_cat = 'A');
Union -------- 进行排序
Union All -------- 不排序
Loc_no, region上有索引
×SELECT ...
FROM location
WHERE loc_id = 10
OR region = 'MELBOURNE';
○SELECT ...
FROM location
WHERE loc_id = 10
UNION ALL
SELECT ...
FROM location
WHERE region = 'MELBOURNE';
×SELECT ...
FROM location
WHERE loc_id = 10
OR loc_id = 20
OR loc_id = 30;
FROM location
WHERE loc_id IN (10, 20, 30);
使用索引时,要考虑以下因素:
1)索引列的计算
2)索引列的增加
3)索引列不要用NOT
4)索引中空值的使用
IS NULL, IS NOT NULL
5)索引列的数据类型的变换
EMP_TYPE为varchar2类型,下列语句使用索引
SELECT ...
FROM emp
WHERE emp_type = 123;
SELECT ...
FROM emp
WHERE TO_NUMBER(emp_type) = 123;
SELECT ...
FROM emp
WHERE emp_type = '123';
增加索引要考虑多种因素,要考虑对更新、插入的影响等。
1)频繁查询不超过大表1%~15%的场合。
2)列的不同值
3)列
4)列
5)同表
$>sqlplus –s /
SQL>@$ORACLE_HOME/rdbms/admin/utlxplan.sql
SQL> commit
SQL> exit
@afe57gc2/users/home/ino 29 >sqlplus sys/****
SQL> @$ORACLE_HOME/sqlplus/admin/plustrce.sql
SQL> drop role plustrace;
:
SQL> grant plustrace to ops$ino;
SQL> exit
@afe57gc2/oracle/product/8.1.7 37 >sqlplus /
SQL> set autotrace on
SQL> select * from wcattori;
执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'WCATTORI'
統計
----------------------------------------------------------
0 recursive calls
12 db block gets
4 consistent gets
0 physical reads
0 redo size
4779 bytes sent via SQL*Net to client
314 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL>
@afe57gc2/oracle/product/8.1.7 40 >sqlplus /
SQL> ALTER SESSION SET TIMED_STATISTICS = true;
SQL> ALTER SESSION SET MAX_DUMP_FILE_SIZE = 500;
SQL> ALTER SESSION SET SQL_TRACE = true;
SQL> SELECT * FROM WCATTORI;
SQL> ALTER SESSION SET SQL_TRACE = false;
SQL> exit
@afe57gc2/users/home/ino 44 >su
Password:
# chmod 777 /oracle/product/8.1.7/rdbms/log/ora_14186_wca1.trc
# exit
@afe57gc2/users/home/ino 46 >tkprof $ORACLE_HOME/rdbms/log/ora_14186_wca1.trc output.txt
TKPROF: Release 8.1.7.2.0 - Production on 木 Apr 18 15:55:17 2002
(c) Copyright 2000 Oracle Corporation. All rights reserved.
備考:ログファイルの出力先
SQL> column name format A20
SQL> column value format A30
SQL> select name, value from v$parameter where name like '%dump_dest';
NAME VALUE
-------------------- ------------------------------
background_dump_dest ?/rdbms/log
user_dump_dest ?/rdbms/log
core_dump_dest ?/dbs
SQL>
@afe57gc2/users/home/ino 47 >cat output.txt (一部抜粋)
SELECT *
FROM
WCATTORI
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.00 0 4 12 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.00 0.00 0 4 12 0
Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 34
Rows Row Source Operation
------- ---------------------------------------------------
0 TABLE ACCESS FULL WCATTORI