很多工具可以看一个SQL的执行计划,通过分析执行计划,作语法分析,逐步可以优化,提高命中率(需要慢慢积累),下面是一个内部培训资料:
ORACLE SQL优化
介绍 
ORACLE执行sql的过程
语法分析 
选择优化模式
生成执行计划
返回结果执行计划(EXPLAIN PLAN)
执行计划指得是ORACLE执行一个SQL语句中做的操作及其顺序。
执行计划的命令格式:
Explain plan [set STATEMENT_ID=‘’ ]
    for
    SQL语句;SQL语句类型仅限于insert、delete、update、select。
其执行计划被放在一个表 PLAN_TABLE里面了
执行计划的三个方面
该语句所用到的表的顺序
每个表的访问路径
用到连结时表的连结方式
举例
    explain plan for
    select * from N_ACNTBASIC a , PSNL_REG_INFO B
   WHERE A.PID =B.PID AND B.PID =:A0;顺便介绍一下主键
PRIMARY KEY
是ORACLE五种约束的一种:
必定存在一个与其名称相同或不同的一个索引(唯一或非唯一),索引列与主键列完全相同。
表示主键的列在该表是唯一且非空的
一个表只有一个主键
目前在我们的SBDEV的表中的主键均是:有一个唯一索引在该主键列上,并且主键列都非空。下面介绍一下执行计划中出现的操作
先建立如下表和索引,以作为例子。
Create table TEST1(
A char(10) constraint PK_TEST1 PRIMARY KEY,
B char(10),
C char(10),
D char(10)
);
Create index DDX_TEST1_B ON TEST(B);
Create index DDX_TEST1_C ON TEST1(C);Create table TEST2(
A char(10) constraint PK_TEST2 PRIMARY KEY,
     D  char(10);
);1. AND-EQUAL
该操作从若干个操作集中接受ROWID,并做交集。用于若干个单列索引都用到的时候。
例:
    select * from test1 where a =:a0 and b = :b0;
 
2. CONCATENATION
该操作接受若干个结果集的值,并将个结果集做UNION ALL. 用于 IN等
例:select * from test1
    where a in(‘0’,’1’);
3. CONNECT BY
当用到 CONNECT BY操作时用到。
举例:
SELECT * FROM TEST1
CONNECT BY A = PRIOR A 
START WITH  A =‘0’;
4。 COUNT STOPKEY
当有ROWNUM <?的操作时。
例:
   select * from test1 where ROWNUM <10;
5.FILTER
该操作过滤掉一些记录集,接受一些记录集。EXISTS ,NOT EXISTS,IN ,NOT IN等会用到
例:SELECT * FROM TEST1 T1
WHERE EXISTS(
SELECT 1 FROM TEST2 WHERE A = T1.A)
6. FOR UPDATE &nbsp; 
当语句有:select … for update时。
例:select * from test1
where a = :a for update;
7.HASH JOIN
对两个结果集做HASH JOIN,用于两个表做等值连接且ORACLE认为用索引不好的情况下。仅限于至少有一个表做过分析或至少有一个表是分区表的情况。
例:select /*+ use_hash(test1,test2) */count(*) from test1,test2 where test1.a = test2.a8。INDEX UNIQUE SCAN
从一个集合里取出<=1条记录。用于唯一索引。
例。Select * from test2
  where a = :a1;
9. INDEX RANGE SCAN
从一个索引中取出若干个ROWID.用于非唯一索引,或唯一索引的列条件不全的情况。 
例:select * from test1 where a = :a1;
10.INDEX FAST FULL SCAN
该操作将会对索引全表扫描,而不用用到表。
例:select count(*) from n_acntbasic11。 INLIST ITERATOR
用于 IN 操作时。
select * from test1
   where a in('1','2')12。 INTERSECTION
执行INTERSECT操作,做两个集合的交集。
例:select * from test1 where a in('2')
            intersect
            select * from test1   where a in('1','2');13. MERGE JOIN
两个结果集各按一个特定的列或列的组合排序,然后执行合并操作。多见于两个大表几乎都是全表扫描的情况。
例:select /*+ use_merge(test1,test2) */* from test1,test2
where test1.d = test2.d;
14.MINUS
集合的减操作.
例: select * from test1 
    minus
      select * from test1 where a =:a;
15.NESTED LOOPS 
嵌套循环。对两个数据集进行操作,其中一个内集,一个外集。ORACLE对外集的每一条数据同内集的每一条记录进行比较,然后得出相应的结果集。
是最常见的JOIN方式,在本数据库中占非常大的比例。
例:Select * from test2,test1
   where test1.a = test2.a and test1.c = :a;
 16.SORT AGGREGATE
用分组函数应用到一组数据上而得到一行记录。
例:select count(*) from test1;
17.SORT UNIQUE
对结果集排序并去掉重复记录。
例:select * from test2  where a in
    (  select a from test1  );
 18.SORT GROUP BY
对一个有GROUP BY操作的执行排序分组。
例:select b,count(*) from test1
group by b
19.TABLE ACCESS FULL
对一个表全表扫描
例: select * from test1;
20. TABLE ACCESS BY INDEX ROWID
对非分区表执行按索引获得ROWID.
例:select * from test2  where a =:a;21. TABLE ACESS BY LOCAL INDEX ROWID 
对分区表执行按local索引检索ROWID
22.TABLE ACESS BY LOCAL INDEX ROWID 
对分区表执行按local索引检索ROWIDHINT
利用hint可以改变执行计划,在执行不太理想的情况下,通过加hint是一个比较方便有效的方法.
Hint是一个提示,提示ORACLE应该干什么,如果hint写的不对,ORACLE会把它当成注释.
格式是: select /*+ your_hint */ …,或update /*+ your_hint */ ,delete,insert同.常用hint
RULE
INDEX
USE_NL
ORDERED
NO_INDEX
FULL
RULE
RULE 该hint提示ORACLE忽略物理方面的性质,纯按逻辑设计去获得执行计划.
格式 select /*+ RULE */…
SELECT /*+ RULE */count(*),sum(A.BCDZJE)
FROM ICB_PAID A,INSU_COMP_BASEINFO B
WHERE A.CBHSHBXDJM=B.SHBXDJM
AND B.SSQX_ID='01';
INDEX
提示某表用索引或用某个索引
格式
 select /*+ index(a) */… from tab a
 select /*+ index(a, DDX_???) */… from tab a
格式1提示表tab用索引
 格式2 提示表tab用索引DDX_???SELECT /*+ index(a) index(b,PK_ICB_PAID) */ count(*),sum(A.BCDZJE) FROM ICB_PAID A,INSU_COMP_BASEINFO B
   WHERE A.CBHSHBXDJM=B.SHBXDJM
  AND B.SSQX_ID='01';
USE_NL
是use nested loops的缩写,提示ORACLE用NESTED LOOPS
格式USE_NL(a,b), USE_NL(a,b,c)
上面的格式分别对表a,b执行NESTED_LOOPS,和对a,b,c执行nested_loops SELECT /*+ use_nl(a,b) */ count(*),sum(A.BCDZJE)
FROM ICB_PAID A,INSU_COMP_BASEINFO B
WHERE A.CBHSHBXDJM=B.SHBXDJM AND B.SSQX_ID='01';ORDERED
提示ORACLE按照从左到右按顺序去关联表.
用法 select /*+ ordered */
例: SELECT /*+ ordered use_nl(a,b) */count(*),sum(A.BCDZJE)
  FROM ICB_PAID A,INSU_COMP_BASEINFO B
WHERE A.CBHSHBXDJM=B.SHBXDJM AND B.SSQX_ID='01';NO_INDEX
提示ORACLE对某个表不用某个索引,或全部索引
格式 
select /*+ no_Index(a) */
select /*+ no_Index(a,DDX_???) */
select /*+ no_index(a) */ * from INSU_COMP_BASEINFO a
   where SHBXDJM = :a;FULL
提示某表做全表扫描.
格式 select /*+ full(a) */
例:重要词汇选择性(Selectivity)一般指索引或索引列
是选出的记录集的数量与总集的数量的比值
举例说明
  Select count(*) from person_info;
选择了8524609行
select count(*) from person_info
    where xm =‘???’
-   假定选择了3行
   对这个表用这个条件的选择性为
   3/ 8524609
选择性(Selectivity)
选择性为 0.0 – 1.0之间的一个数
=0 表示将选出0条记录,1 表示选出所有记录
选择率越小说明用该条件速度越快.
当表被分析过后,ORACLE数据字典里会记录着各列的最大值,最小值,不同的值的数目,总数目等结果.也记录着各索引的不同值的数目和总数目等
索引的选择性<=0.20时认为用该索引是有效的.  
select zhzt_id,count(*) from n_acntbasic
   group by zhzt_id
   order by 2;
43     15
42        145
23        193
41        736
50     20288
12     30802
11   170887
32   365583
22   470919
31   514832
21 3843391DRIVER(驱动表)
所谓驱动表,指要先从那表开始本语句.
select count(*),sum(A.BCDZJE)
  from ICB_PAID A,INSU_COMP_BASEINFO B
where A.CBHSHBXDJM=B.SHBXDJM and B.SSQX_ID='01';如何来优化(多数情况)
首先要选好驱动表,该表相对其他表或者是量较小,或者是用了一个较好的索引.
然后按顺序执行nest loops,保证余下各表要用上较好的索引.

解决方案 »

  1.   

    很多工具可以看一个SQL的执行计划,通过分析执行计划,作语法分析,逐步可以优化,提高命中率(需要慢慢积累),下面是一个内部培训资料:
    ORACLE SQL优化
    介绍 
    ORACLE执行sql的过程
    语法分析 
    选择优化模式
    生成执行计划
    返回结果执行计划(EXPLAIN PLAN)
    执行计划指得是ORACLE执行一个SQL语句中做的操作及其顺序。
    执行计划的命令格式:
    Explain plan [set STATEMENT_ID=‘’ ]
        for
        SQL语句;SQL语句类型仅限于insert、delete、update、select。
    其执行计划被放在一个表 PLAN_TABLE里面了
    执行计划的三个方面
    该语句所用到的表的顺序
    每个表的访问路径
    用到连结时表的连结方式
    举例
        explain plan for
        select * from N_ACNTBASIC a , PSNL_REG_INFO B
       WHERE A.PID =B.PID AND B.PID =:A0;顺便介绍一下主键
    PRIMARY KEY
    是ORACLE五种约束的一种:
    必定存在一个与其名称相同或不同的一个索引(唯一或非唯一),索引列与主键列完全相同。
    表示主键的列在该表是唯一且非空的
    一个表只有一个主键
    目前在我们的SBDEV的表中的主键均是:有一个唯一索引在该主键列上,并且主键列都非空。下面介绍一下执行计划中出现的操作
    先建立如下表和索引,以作为例子。
    Create table TEST1(
    A char(10) constraint PK_TEST1 PRIMARY KEY,
    B char(10),
    C char(10),
    D char(10)
    );
    Create index DDX_TEST1_B ON TEST(B);
    Create index DDX_TEST1_C ON TEST1(C);Create table TEST2(
    A char(10) constraint PK_TEST2 PRIMARY KEY,
         D  char(10);
    );1. AND-EQUAL
    该操作从若干个操作集中接受ROWID,并做交集。用于若干个单列索引都用到的时候。
    例:
        select * from test1 where a =:a0 and b = :b0;
     
    2. CONCATENATION
    该操作接受若干个结果集的值,并将个结果集做UNION ALL. 用于 IN等
    例:select * from test1
        where a in(‘0’,’1’);
    3. CONNECT BY
    当用到 CONNECT BY操作时用到。
    举例:
    SELECT * FROM TEST1
    CONNECT BY A = PRIOR A 
    START WITH  A =‘0’;
    4。 COUNT STOPKEY
    当有ROWNUM <?的操作时。
    例:
       select * from test1 where ROWNUM <10;
    5.FILTER
    该操作过滤掉一些记录集,接受一些记录集。EXISTS ,NOT EXISTS,IN ,NOT IN等会用到
    例:SELECT * FROM TEST1 T1
    WHERE EXISTS(
    SELECT 1 FROM TEST2 WHERE A = T1.A)
    6. FOR UPDATE &nbsp; 
    当语句有:select … for update时。
    例:select * from test1
    where a = :a for update;
    7.HASH JOIN
    对两个结果集做HASH JOIN,用于两个表做等值连接且ORACLE认为用索引不好的情况下。仅限于至少有一个表做过分析或至少有一个表是分区表的情况。
    例:select /*+ use_hash(test1,test2) */count(*) from test1,test2 where test1.a = test2.a8。INDEX UNIQUE SCAN
    从一个集合里取出<=1条记录。用于唯一索引。
    例。Select * from test2
      where a = :a1;
    9. INDEX RANGE SCAN
    从一个索引中取出若干个ROWID.用于非唯一索引,或唯一索引的列条件不全的情况。 
    例:select * from test1 where a = :a1;
    10.INDEX FAST FULL SCAN
    该操作将会对索引全表扫描,而不用用到表。
    例:select count(*) from n_acntbasic11。 INLIST ITERATOR
    用于 IN 操作时。
    select * from test1
       where a in('1','2')12。 INTERSECTION
    执行INTERSECT操作,做两个集合的交集。
    例:select * from test1 where a in('2')
                intersect
                select * from test1   where a in('1','2');13. MERGE JOIN
    两个结果集各按一个特定的列或列的组合排序,然后执行合并操作。多见于两个大表几乎都是全表扫描的情况。
    例:select /*+ use_merge(test1,test2) */* from test1,test2
    where test1.d = test2.d;
    14.MINUS
    集合的减操作.
    例: select * from test1 
        minus
          select * from test1 where a =:a;
    15.NESTED LOOPS 
    嵌套循环。对两个数据集进行操作,其中一个内集,一个外集。ORACLE对外集的每一条数据同内集的每一条记录进行比较,然后得出相应的结果集。
    是最常见的JOIN方式,在本数据库中占非常大的比例。
    例:Select * from test2,test1
       where test1.a = test2.a and test1.c = :a;
     16.SORT AGGREGATE
    用分组函数应用到一组数据上而得到一行记录。
    例:select count(*) from test1;
    17.SORT UNIQUE
    对结果集排序并去掉重复记录。
    例:select * from test2  where a in
        (  select a from test1  );
     18.SORT GROUP BY
    对一个有GROUP BY操作的执行排序分组。
    例:select b,count(*) from test1
    group by b
    19.TABLE ACCESS FULL
    对一个表全表扫描
    例: select * from test1;
    20. TABLE ACCESS BY INDEX ROWID
    对非分区表执行按索引获得ROWID.
    例:select * from test2  where a =:a;21. TABLE ACESS BY LOCAL INDEX ROWID 
    对分区表执行按local索引检索ROWID
    22.TABLE ACESS BY LOCAL INDEX ROWID 
    对分区表执行按local索引检索ROWIDHINT
    利用hint可以改变执行计划,在执行不太理想的情况下,通过加hint是一个比较方便有效的方法.
    Hint是一个提示,提示ORACLE应该干什么,如果hint写的不对,ORACLE会把它当成注释.
    格式是: select /*+ your_hint */ …,或update /*+ your_hint */ ,delete,insert同.常用hint
    RULE
    INDEX
    USE_NL
    ORDERED
    NO_INDEX
    FULL
    RULE
    RULE 该hint提示ORACLE忽略物理方面的性质,纯按逻辑设计去获得执行计划.
    格式 select /*+ RULE */…
    SELECT /*+ RULE */count(*),sum(A.BCDZJE)
    FROM ICB_PAID A,INSU_COMP_BASEINFO B
    WHERE A.CBHSHBXDJM=B.SHBXDJM
    AND B.SSQX_ID='01';
    INDEX
    提示某表用索引或用某个索引
    格式
     select /*+ index(a) */… from tab a
     select /*+ index(a, DDX_???) */… from tab a
    格式1提示表tab用索引
     格式2 提示表tab用索引DDX_???SELECT /*+ index(a) index(b,PK_ICB_PAID) */ count(*),sum(A.BCDZJE) FROM ICB_PAID A,INSU_COMP_BASEINFO B
       WHERE A.CBHSHBXDJM=B.SHBXDJM
      AND B.SSQX_ID='01';
    USE_NL
    是use nested loops的缩写,提示ORACLE用NESTED LOOPS
    格式USE_NL(a,b), USE_NL(a,b,c)
    上面的格式分别对表a,b执行NESTED_LOOPS,和对a,b,c执行nested_loops SELECT /*+ use_nl(a,b) */ count(*),sum(A.BCDZJE)
    FROM ICB_PAID A,INSU_COMP_BASEINFO B
    WHERE A.CBHSHBXDJM=B.SHBXDJM AND B.SSQX_ID='01';ORDERED
    提示ORACLE按照从左到右按顺序去关联表.
    用法 select /*+ ordered */
    例: SELECT /*+ ordered use_nl(a,b) */count(*),sum(A.BCDZJE)
      FROM ICB_PAID A,INSU_COMP_BASEINFO B
    WHERE A.CBHSHBXDJM=B.SHBXDJM AND B.SSQX_ID='01';NO_INDEX
    提示ORACLE对某个表不用某个索引,或全部索引
    格式 
    select /*+ no_Index(a) */
    select /*+ no_Index(a,DDX_???) */
    select /*+ no_index(a) */ * from INSU_COMP_BASEINFO a
       where SHBXDJM = :a;FULL
    提示某表做全表扫描.
    格式 select /*+ full(a) */
    例:重要词汇选择性(Selectivity)一般指索引或索引列
    是选出的记录集的数量与总集的数量的比值
    举例说明
      Select count(*) from person_info;
    选择了8524609行
    select count(*) from person_info
        where xm =‘???’
    -   假定选择了3行
       对这个表用这个条件的选择性为
       3/ 8524609
    选择性(Selectivity)
    选择性为 0.0 – 1.0之间的一个数
    =0 表示将选出0条记录,1 表示选出所有记录
    选择率越小说明用该条件速度越快.
    当表被分析过后,ORACLE数据字典里会记录着各列的最大值,最小值,不同的值的数目,总数目等结果.也记录着各索引的不同值的数目和总数目等
    索引的选择性<=0.20时认为用该索引是有效的.  
    select zhzt_id,count(*) from n_acntbasic
       group by zhzt_id
       order by 2;
    43     15
    42        145
    23        193
    41        736
    50     20288
    12     30802
    11   170887
    32   365583
    22   470919
    31   514832
    21 3843391DRIVER(驱动表)
    所谓驱动表,指要先从那表开始本语句.
    select count(*),sum(A.BCDZJE)
      from ICB_PAID A,INSU_COMP_BASEINFO B
    where A.CBHSHBXDJM=B.SHBXDJM and B.SSQX_ID='01';如何来优化(多数情况)
    首先要选好驱动表,该表相对其他表或者是量较小,或者是用了一个较好的索引.
    然后按顺序执行nest loops,保证余下各表要用上较好的索引.