• day18——sql优化


    1. 选用适合的ORACLE优化器
     ORACLE的优化器共有3种:
    a. RULE (基于规则) b. COST (基于成本) c. CHOOSE (选择性)
     设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖.
    为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze 命令,以增加数据库中的对象统计信息(object statistics)的准确性.
    如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器.
     在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器


    SQL> show parameter optimizer_mode;

    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ---------
    optimizer_mode                       string      ALL_ROWS

    ALL_ROWS:是一种基于成本的优化器,它将选择一种在最短时间内返回所有数据的执行计划



    访问表的方式
    全表扫描:

      采用顺序访问的方式访问每条记录,实际过程中oracle一次读入多个数据块来加快全表扫描
      实际数据库中通过参数db_file_multiblock_read_count来控制一次读取的块的数量.对该参数进行合理配置可以优化I/O
    SQL> show parameter db_file_multiblock_read_count

    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- -------
    db_file_multiblock_read_count        integer     16


    ===================================================
    2. 访问Table的方式
     ORACLE 采用两种访问表中记录的方式:
     a. 全表扫描
    全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描.
     b. 通过ROWID访问表
    你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.


    3. 共享SQL语句
     为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用.可惜的是ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询.

    A. 字符级的比较:
    当前被执行的语句和共享池中的语句必须完全相同.
    例如:
    SELECT * FROM EMP;
    和下列每一个都不同
    SELECT * from EMP;
    Select * From Emp;
    SELECT * FROM emp;
    =======================================

     B. 两个语句所指的对象必须完全相同:
    例如:
    用户 对象名 如何访问
    Jack sal_limit private synonym
    Work_city public synonym
    Plant_detail public synonym
    Jill sal_limit private synonym

    =======================================
    C.两个sql语句中必须使用相同的绑定变量
    =======================================
    D.选择最有效率的表名顺序
    from后面连接多表,最后面的表为基础表(最先被处理),选择条目少的放在from的最后面,oracle处理多表时会排序及合并,先扫描基础表排序,然后扫描下一个表并于第一个表进行合并.

    t1 100000条记录
    t2 1 条记录

    显示sql运行时间
    sql>set timing on
    选择t2表做基础表(效率最高)
    sql>select count(*) from t1,t2 (执行时间很短)

    sql>select count(*) from t2,t1 (执行时间长)

    =======================================

    E.select 子句中避免使用 *
    =======================================

    F.减少访问数据库的次数

    1.select * from emp where emp_no=123;
      select * from emp where emp_no=321; 
      (执行2次,低效)

    2.select * from emp a,emp b where a.emp_no=123 and b.emp_no=321;
      (执行1次,高效)
    =======================================

    G.使用 decode函数

    decode 函数
    只有ORACLE公司的SQL提供了此函数

    SELECT DECODE(SIGN(5 – 5), 1,
                ’Is Positive’, -1, ’Is Negative’, ‘Is Zero’)
                FROM DUAL 

    select decode(SIGN(5 - 5),1,
    'Is Positive',-1,
    'Is Negative','Is Zero') FROM DUAL;


    例1:
    工资在8000元以下的将加20%;工资在8000元以上的加15%
    select decode(sign(sal-8000),1,sal*1.15,-1,sal*1.2)gongzi,sal from emp
    ((sign()函数根据某个值是0、正数还是负数,分别返回0、1、-1))

    例2:
    比如我要查询某班男生和女生的数量分别是多少? 
    通常我们这么写:

    select count(*) from 表 where 性别 = 男;

    select count(*) from 表 where 性别 = 女;

    要想显示到一起还要union一下,太麻烦了

    用decode呢,只需要一句话

    select count(decode(性别,男,1,null)),count(decode(性别,女,1,null)) from 表

    =======================================
    H.用 truncate 替换delete
      尽量多的使用commit

    =======================================
    I.having使用

    HAVING 语法与 WHERE 语法类似,但 HAVING 可以包含聚合函数。HAVING 子句可以引用选择列表中出现的任意项。

    例:
    找出那些平均工资在$2000以上的部门
    SQL> select deptno,avg(sal) avg_sal from emp
      2  group by deptno having avg(sal) >2000;


    =======================================
    case ..when
    case 语句带有选择效果知返回第一个条件满足要求的语句,即语句一语句二都的判断都为 true ,返回排在前面的。

    SELECT ename,
    (CASE deptno
      WHEN 10 THEN 'ACCOUNTING'
      WHEN 20 THEN 'RESEARCH'
      WHEN 30 THEN 'SALES'
      WHEN 40 THEN 'OPERATIONS'
      ELSE 'Unassigned'
      END ) as Department
    FROM emp;


    SELECT ename, sal, deptno,
    CASE
     WHEN sal <= 500 then 0
     WHEN sal > 500 and sal<1500  then 100
     WHEN sal >= 1500 and sal < 2500  and deptno=10 then 200
     WHEN sal > 1500  and sal < 2500 and deptno=20 then 500
     WHEN sal >= 2500 then 300
     ELSE 0
    END "bonus"
    FROM emp;


    =======================================

    删除重复记录

    最高效的删除重复记录方法 ( 因为使用了ROWID)
    DELETE FROM EMP E
    WHERE E.ROWID > (SELECT MIN(X.ROWID) 
                       FROM EMP X
                       WHERE X.EMP_NO = E.EMP_NO);



    =========================================
    用union/union all 替换 or(适用于索引列)
    SQL> create table a as select * from dba_objects;
    SQL> create table b as select * from dba_objects;
    SQL> create index ia on a(object_id);
    SQL> create index ib on b(object_id);

    SQL> set autotrace traceonly
    SQL> select owner from a where object_id=22 or object_id in
        (select data_object_id from b where object_id=22);

     149921  consistent gets
              0  physical reads


    优化为:
    SQL> select owner from a where object_id=22
        union all
        select owner from a where object_id <>22
        and object_id in (select data_object_id from b where object_id=22);
     
            10  consistent gets
              0  physical reads
    逻辑读减少了很多

    ==========================================

    执行顺序: 
    1.select 列列表 from 表列表名/视图列表名 where 条件.   
            先where 后select      
    2.select 列列表 from 表列表名/视图列表名 where 条件 group by (列列表) having 条件      
          先where 再group 再having 后select           
    3.select 列列表 from 表列表名/视图列表名 where 条件 group by (列列表) having 条件 order by 列列表   
          先where 再group 再having 再select 后order 
    4.select 列列表 from 表1 join 表2 on 表1.列1=表2.列1...join 表n on 表n.列1=表(n-1).列1 where 表1.条件 and 表2.条件...表n. 
    先join 再where 后select
    有个问题  如果 条件字句顺序是固定的   

    ==========================================
    J.使用同义词
    1. 同义词是表、索引、视图等模式对象的一个别名。oracle数据库只在数据字典中保存其定义描述,同义词不占用任何实际的物理空间。

    2. 使用同义词优点:避免当管理员对数据库对象做出修改和变动之后,必须重新编译应用程序。使用同义词后,即使引用的对象发生变化,也只需要在数据库中对同义词进行修改,而不对应用程序做任何修改。

    3. 同义词分类:公有同义词、私有同义词。公有同义词由public用户组拥有,数据库中的所有用户都可以使用公有同义词。
    私有同义词只被创建它的用户所拥有,只能由该用户以及被授权的其他用户使用。



    4. 创建公有同义词:
    SQL> alter user scott account unlock;
    SQL> password scott

    SQL> create user sq1 identified by abc123 account unlock;
    SQL> grant create session to sq1;
    SQL> grant create table to sq1;
    SQL> alter user sq1 quota unlimited on users;

    创建公有同义词:sys下
    SQL> create public synonym eemp for scott.emp;

    SQL> grant public to sq1; (把public角色赋予sq1用户)
    SQL> grant select on scott.emp to sq1;

    SQL> conn sq1/abc123
    SQL> select * from eemp;

    5.创建私有同义词
    sys下
    SQL> create synonym aaa for scott.emp;
    SQL> select * from aaa;

    SQL> grant create synonym to scott;

    SQL> conn scott/abc123;(scott登录)
    SQL> create synonym bbb for emp;
    SQL> select * from bbb;

    6.查看同义词
    SQL> desc dba_synonyms;
    SQL> desc user_synonyms;


    7.删除同义词
    SQL> drop synonym aaa;















  • 相关阅读:
    对于近期学习上的复习与整理
    ACM的奇计淫巧_输入挂
    hdu2602 DP (01背包)
    hdu 1723 DP/递推
    hdu1428 记忆化搜索(BFS预处理最短路径和+DP+DFS)
    hdu1355
    hdu1331&&hdu1579记忆化搜索(DP+DFS)
    hdu1257 dp(最长上升子序列)
    hdu1208 dp
    hdu 1203 dp(关于概率的```背包?)
  • 原文地址:https://www.cnblogs.com/xiaoxiao5ya/p/697cc2029392287119f7fbfe82fef6a1.html
Copyright © 2020-2023  润新知