4.
选择
最有效率的表名
顺
序
(
只在基于
规则
的
优
化器中有效
)
ORACLE 的解析器按照从右到左的 顺 序 处 理 FROM 子句中的表名 , 因此 FROM 子句中写在最后的表 ( 基 础 表 driving table) 将被最先 处 理 . 在 FROM 子句中包含多个表的情况下 , 你必 须选择记录 条数最少的表作 为 基 础 表 . 当 ORACLE 处 理多个表 时 , 会运用排序及合并的方式 连 接它 们 . 首先 , 扫 描第一个表 (FROM 子句中最后的那个表 ) 并 对记录进 行派序 , 然后 扫 描第二个表 (FROM 子句中最后第二个表 ), 最后将所有从第二个表中 检 索出的 记录 与第一个表中合适 记录进 行合并 .
例如 :
ORACLE 的解析器按照从右到左的 顺 序 处 理 FROM 子句中的表名 , 因此 FROM 子句中写在最后的表 ( 基 础 表 driving table) 将被最先 处 理 . 在 FROM 子句中包含多个表的情况下 , 你必 须选择记录 条数最少的表作 为 基 础 表 . 当 ORACLE 处 理多个表 时 , 会运用排序及合并的方式 连 接它 们 . 首先 , 扫 描第一个表 (FROM 子句中最后的那个表 ) 并 对记录进 行派序 , 然后 扫 描第二个表 (FROM 子句中最后第二个表 ), 最后将所有从第二个表中 检 索出的 记录 与第一个表中合适 记录进 行合并 .
例如 :
表
TAB1 16,384
条
记录
表 TAB2 1 条 记录
选择 TAB2 作 为 基 础 表 ( 最好的方法 )
select count(*) from tab1,tab2 执 行 时间 0.96 秒
选择 TAB2 作 为 基 础 表 ( 不佳的方法 )
select count(*) from tab2,tab1 执 行 时间 26.09 秒
如果有 3 个以上的表 连 接 查询 , 那就需要 选择 交叉表 (intersection table) 作 为 基 础 表 , 交叉表是指那个被其他表所引用的表 .
例如 :
EMP 表描述了 LOCATION 表和 CATEGORY 表的交集 .
SELECT *
FROM LOCATION L ,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
将比下列 SQL 更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
5. WHERE 子句中的 连 接 顺 序.
ORACLE 采用自下而上的 顺 序解析 WHERE 子句 , 根据 这 个原理 , 表之 间 的 连 接必 须 写在其他 WHERE 条件之前 , 那些可以 过滤 掉最大数量 记录 的条件必 须 写在 WHERE 子句的末尾 .
例如 :
( 低效 , 执 行 时间 156.3 秒 )
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO);
( 高效 , 执 行 时间 10.6 秒 )
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’;
6. SELECT 子句中避免使用 ‘ * ‘
当你想在 SELECT 子句中列出所有的 COLUMN 时 , 使用 动态 SQL 列引用 ‘*’ 是一个方便的方法 . 不幸的是 , 这 是一个非常低效的方法 . 实际 上 ,ORACLE 在解析的 过 程中 , 会将 ’*’ 依次 转换 成所有的列名 , 这 个工作是通 过查询 数据字典完成的 , 这 意味着将耗 费 更多的 时间 .
表 TAB2 1 条 记录
选择 TAB2 作 为 基 础 表 ( 最好的方法 )
select count(*) from tab1,tab2 执 行 时间 0.96 秒
选择 TAB2 作 为 基 础 表 ( 不佳的方法 )
select count(*) from tab2,tab1 执 行 时间 26.09 秒
如果有 3 个以上的表 连 接 查询 , 那就需要 选择 交叉表 (intersection table) 作 为 基 础 表 , 交叉表是指那个被其他表所引用的表 .
例如 :
EMP 表描述了 LOCATION 表和 CATEGORY 表的交集 .
SELECT *
FROM LOCATION L ,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
将比下列 SQL 更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
5. WHERE 子句中的 连 接 顺 序.
ORACLE 采用自下而上的 顺 序解析 WHERE 子句 , 根据 这 个原理 , 表之 间 的 连 接必 须 写在其他 WHERE 条件之前 , 那些可以 过滤 掉最大数量 记录 的条件必 须 写在 WHERE 子句的末尾 .
例如 :
( 低效 , 执 行 时间 156.3 秒 )
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO);
( 高效 , 执 行 时间 10.6 秒 )
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’;
6. SELECT 子句中避免使用 ‘ * ‘
当你想在 SELECT 子句中列出所有的 COLUMN 时 , 使用 动态 SQL 列引用 ‘*’ 是一个方便的方法 . 不幸的是 , 这 是一个非常低效的方法 . 实际 上 ,ORACLE 在解析的 过 程中 , 会将 ’*’ 依次 转换 成所有的列名 , 这 个工作是通 过查询 数据字典完成的 , 这 意味着将耗 费 更多的 时间 .
7. 减少 访问 数据 库 的次数
当 执 行 每 条 SQL 语 句 时 , ORACLE 在内部 执 行了 许 多工作 : 解析 SQL 语 句 , 估算索引的利用率 , 绑 定 变 量 , 读 数据 块 等等 . 由此可 见 , 减少 访问 数据 库 的次数 , 就能 实际 上减少 ORACLE 的工作量 .
例如 ,
以下有三 种 方法可以 检 索出雇 员 号等于 0342 或 0291 的 职员 .
方法 1 ( 最低效 )
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 342;
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 291;
方法 2 ( 次低效 )
DECLARE
CURSOR C1 (E_NO NUMBER) IS
SELECT EMP_NAME,SALARY,GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO
OPEN C1(291);
FETCH C1 INTO
CLOSE C1;
END;
方法 3 ( 高效 )
SELECT A.EMP_NAME , A.SALARY , A.GRADE,
B.EMP_NAME , B.SALARY , B.GR ADE
FROM EMP A,EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291;
注意 :
在 SQL*Plus , SQL*Forms 和 Pro*C 中重新 设 置 ARRAYSIZE 参数 , 可以增加 每 次数据 库访问 的 检 索数据量 , 建 议值为 200
END;
方法 3 ( 高效 )
SELECT A.EMP_NAME , A.SALARY , A.GRADE,
B.EMP_NAME , B.SALARY , B.GR ADE
FROM EMP A,EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291;
注意 :
在 SQL*Plus , SQL*Forms 和 Pro*C 中重新 设 置 ARRAYSIZE 参数 , 可以增加 每 次数据 库访问 的 检 索数据量 , 建 议值为 200