SlideShare a Scribd company logo
SQL语句编写优化和基本原理总结


           王崇安 2012-08-24
   http://wangchongan.com
   http://weibo.com/wangchongan




                 欢迎访问技术博客: wangchongan.com
共享SQL语句
为不重复解析相同的SQL,在第一次解析后,ORACLE将会把SQL语句存放在内存中
(SGA的共享池中),以在下次执行同样的SQL时直接获得解析后的SQL及最好的执行路径。

注意:ORACLE只对单表提供高速缓冲,不适用于多表连接查询。

共享语句必须满足3个条件:
1、字符级的比较
如:select * from wl_trade; 和 select *   from wl_trade; 不同
2、两个语句所指的对象必须完全相同
3、两个SQL语句中比如使用相同的名字的绑定变量。
   (赋值相同也不行)                                    用户         对象名          访问类型
                                               lpwl    lp_trade     private synonym
                                                       lp_product   public synonym
                                               lpoc    lp_trade     private synonym
                                                       lp_product   public synonym
Overview of SGA
 System global area (SGA)
 The SGA is a group of shared memory structures, known as SGA components, that contain data and
 control information for one Oracle Database instance. The SGA is shared by all server and background
 processes. Examples of data stored in the SGA include cached data blocks and shared SQL areas.




资料来源:http://docs.oracle.com/cd/B28359_01/server.111/b28318/memory.htm
表名顺序(在RBO中)
• 按照表记录数: 大 -> 小
• 表书写顺序:  左 -> 右
因为表间连接时,最右边的表会被放到嵌套循环的最外层。最外层循环
越少,效率越高。
WHERE子句中条件的顺序
ORACLE采用自下而上(自右向左)的顺序解析WHERE子句。

 表之间的连接必须写在其他条件之前

 可以过滤掉最大记录的条件必须写在WHERE子句末尾


 应用场景举例:查找某个SPU的所有订单的基本信息

                              SQL语句                             性能效果
 Select t.trade_id, o.order_id, o.product_id from wl_trade t,
 wl_order o where o.product_id = ‘289098760’ and t.id =          低效
 o.inner_trade_id

 Select t.trade_id, o.order_id, o.product_id from wl_trade t,
 wl_order o where t.id = o.inner_trade_id and o.product_id =     高效
 ‘289098760’
SELECT子句中避免使用*
• 需列出全部的COLUMN时,不建议使用*
因为ORACLE在解析SQL的过程中会将*转换成所有的列名,这个环节是通过
查数据字典完成的,意味性能的损耗。
删除重复记录
• 最高效的删除重复记录的方法
  场景举例:删除手工单引起的重复的销售订单

 delete from wl_trade t1
 where t1.rowid > (
        select min(x.rowid)
        from wl_trade t2
        where t2.trade_id = t1.trade_id);

 因为使用ROWID,所以高效
•
           用TRUNCATE替代DELETE
     表记录删除时,采用回滚段(rollback segments)来存放可以被恢复的信息。rollback时oracle将
     会将数据恢复到执行删除命令前的状况。
•    而当使用truncate时,回滚段不再存放可恢复信息。资源利用少,响应快。
•    delete属DML,truncate属DDL(隐式事务,会自动提交)
•    delete将被删数据块标记为无效(unused),truncate将表的高水位线HWM标为0
•    再扫描时,delete后的数据由于高水位线没有变化,还是会扫描原来所有数据块,性能差


     应用场景举例:4PL监控看板统计任务定时truncate
•
                   多使用COMMIT
    由上条大至推理可知:尽可能地多使用COMMIT,但,还不止这个原因。。。



COMMIT所释放的资源:

1、回滚段上用于恢复数据的信息

2、被程序语句获得的锁。如:4PL中库存更新操作(下图)

3、redo log buffer中的空间

4、为管理上面资源的内部花费
用WHERE子句替换HAVING子句
• HAVING中的条件一般用于集合函数的比较,如count(),否则一
    般条件应写在WHERE子句中
 因为HAVING只会在检索出所有记录后才进行对结果集的过滤,这个处理需要总计或排序
 等操作。如果通过WHERE子句限制记录条数,就能减少这个开销。



  应用场景举例:4PL监控看板中计算合单量SQL

SELECT G.LSO_FATHER_ID                      SELECT G.LSO_FATHER_ID
 FROM WL_MONITOR_GRAND_ORDER G               FROM WL_MONITOR_GRAND_ORDER G
WHERE G.LSO_FATHER_ID != 0                   WHERE
 AND G.O_PRODUCT_ID = '10000'                 G.O_PRODUCT_ID = '10000'
 AND G.T_PLATFORM_CODE = 'TB'                 AND G.T_PLATFORM_CODE = 'TB'
 AND G.T_SUPPLIER_CHANNEL = 0                 AND G.T_SUPPLIER_CHANNEL = 0
 AND G.O_GMT_PAY >= '2012-08-01 00:00:00'     AND G.O_GMT_PAY >= '2012-08-01 00:00:00'
 AND G.O_GMT_PAY <= '2012-08-21 00:00:00'     AND G.O_GMT_PAY <= '2012-08-21 00:00:00'
 AND G.O_PAY_STATUS != 'TRADE_CLOSED'         AND G.O_PAY_STATUS != 'TRADE_CLOSED'
 AND G.LSO_IS_DELETED='N'                     AND G.LSO_IS_DELETED='N'
GROUP BY G.LSO_FATHER_ID                     GROUP BY G.LSO_FATHER_ID
HAVING COUNT(G.LSO_FATHER_ID)>1             HAVING COUNT(G.LSO_FATHER_ID)>1
                                              AND G.LSO_FATHER_ID != 0
EXISTS?IN?
并不是简单的都要使用EXISTS替代IN
in是对外表和内表作Hash Join(哈希连接)
而exist是对外表和内表做了一个Nested loop(嵌套连接)

 例如:表A(小表),表B(大表),CC列上有索引
select * from A where cc in (select cc from B) – 低效
A是小表,CC索引优势不明显,B表索引没充分利用


select * from A where exists(select cc from B where cc=A.cc) – 高效
遍历A,但小表次数也少,用到了B表索引

补充点:Not in内外表都做全表扫描,没用到索引,而Not exists子查询仍能用到索引

                                  子句                  使用策略
                         EXISTS                  小表大表
                         IN                      大表小表
                         NOT EXISTS              尽量用
                         NOT IN                  尽量不用
用EXISTS替换DISTINCT
• 一对多表查询时,避免使用DISTINCT,可考虑用EXISTS替
  换

   应用场景举例:查询所有被用户购买过的4PL-SPU

                           SQL                  idb测试用时   比较

 select distinct p.id
   from wl_product p, wl_logistics_suborder o             性能低
 where p.id = o.spu_id

 select p.id
   from wl_product p
  where exists (select 1                                  性能高
                from wl_logistics_suborder o
              where o.spu_id = p.id)
用EXPLAIN PLAN分析SQL
解读顺序:从里至外,从上至下,同层操作最小操作号先解读
ORACLE对索引访问模式
•   唯一索引扫描(index unique scan)

    返回单个ROWID,存在UNIQUE或PRIMARY KEY时

•   索引范围扫描(index range scan)

    存取多行数据,在唯一索引上使用范围操作符 (>, <, >=, <=, between)

    组合索引上,只使用部分列进行查询,导致查询出多行

    对非唯一索引上的任何查询

•   索引全扫描(index full scan)

    查询返回的字段必须全部来自索引

•   索引快速扫描(index fast full scan)

    扫描索引中的所有数据块,与index full scan显著区别是不对结果集排序,基于该特点可使用多块读、

并行读以提高吞吐量和缩短时间。
索引选择之唯一和非唯一索引
• 如果查询条件存在使用唯一和非唯一索引,则
  ORACLE将使用唯一索引,完全忽略非唯一索引
索引选择之多个平级索引
•   唯一性索引优先级高于非唯一性索引

    只适用于索引列和常量比较

•   相同表中同等级索引时

    WHERE子句中最先被引用的索引优先级高

•   不同表间同等级索引时

    FROM子句表顺序右至左,右边表的索引优先被使用

•   多表多索引均可使用时

    ORACLE会同时使用并对记录进行合并,检索出对所有索引都有效的记录
索引选择之等式和范围比较
• WHERE子句有索引列但ORACLE无法合并使
  用,将采用范围比较




 LPWL.WL_ORDER_IND6:只有PRODUCT_Id的索引被用到
索引选择之不明确的索引等级
• 当ORACLE无法确定索引的等级时,一般来说优化器将使用WHERE子句
 最前面那个。

  但ORACLE也很聪明
强制索引失效
• 通过+number 或 || varchar 形式可使索引失效
一般强制索引失效的调优仅用于个别SQL,
绝大部分情况下ORACLE本身已能选择很佳的执行路径。

在使用索引失效前需确认好索引列是否已建索引?


 场景举例:查询某商品指定SKU的销售订单

  前提:product_id、skuid 分别有非唯一索引

select * from wl_order where
product_id = ‘18513216738’ and skuid = ‘20979202070’;

select * from wl_order where
product_id || ‘’ = ‘18513216738’ and skuid = ‘20979202070’;
避免在索引列使用NULL或NOT NULL
• 单例索引如包含空值,索引中不存在此记录
• 联合索引中列全空,索引中不存在此记录
• 联合索引中存在至少一列不为空,索引中存在此记录
总是使用组合索引第一列
• 如果是组合索引,则只有第一列使用时,优化器才会使用
  该索引
 举例演示:测试4PL的wl_order表的WL_ORDER_SID_IND(SUPPLIER_ID,LOGISTICS_STATUS)索引



                                 使用了第一列SUPPLIER_ID,优化器走了索引




                        不使用第一列SUPPLIER_ID,导致全表扫描
简单飘过
1.   不要在索引列上使用计算
2.   不要在索引列上使用NOT
3.   用 >= 替代 >
4.   避免改变索引列的类型
5.   !=号可能导致不走索引
• 监控看板案例      使用Hints-案例分析




不匹配的别名导致执行路径不生效,执行约2分钟                     调整后很快,约200ms

  延伸知识:
  1. ordered根据 from 后面表的顺序join,从左到右,左边的表做驱动表
  2. /*+use_nl(t2,t) */ 提示走nest loop,但没有提示t2还是t为驱动表
  3. /*+ ordered use_nl(t2,t) */提示走nest loop,order提示的是from后面的第一个表为驱动表
  4. /*+ leading(t2) use_nl(t) */ 直接提示t2为驱动表

  结论:use_nl不能让优化器确定谁是驱动表谁是被驱动的表,use_nl(t,t2)也没有指出哪个是驱
  动表,这时候我们需要使用ordered,leading来强制指定驱动表,以达到我们的目的
谢谢大家!

More Related Content

PDF
Raising The MySQL Bar-Manyi Lu
PDF
My sql 使用规范
PPT
Java SE 8 技術手冊第 10 章 - 輸入輸出
PPT
20120324 sql server 2012新特性by_rico
PPT
PHP
PPT
腾讯大讲堂48 数据库查询优化浅析
PDF
Oracle 索引介紹
Raising The MySQL Bar-Manyi Lu
My sql 使用规范
Java SE 8 技術手冊第 10 章 - 輸入輸出
20120324 sql server 2012新特性by_rico
PHP
腾讯大讲堂48 数据库查询优化浅析
Oracle 索引介紹

What's hot (13)

PPT
Mysql的索引及优化策略
PDF
Kid171 chap03 traditional Chinese Version
PPT
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
PPT
Sql Server 高级技巧系列之三整体优化
PDF
Spark tutorial
PDF
PostGIS 初入門應用
PPT
Java SE 8 技術手冊第 5 章 - 物件封裝
PDF
Java SE 7 技術手冊投影片第 10 章 - 輸入輸出
PPT
Sql Server 高级技巧系列之一:索引详解
PDF
Oracle 資料庫檔案介紹
PDF
Oracle 資料庫建立
PPTX
5, initialization & cleanup
Mysql的索引及优化策略
Kid171 chap03 traditional Chinese Version
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Sql Server 高级技巧系列之三整体优化
Spark tutorial
PostGIS 初入門應用
Java SE 8 技術手冊第 5 章 - 物件封裝
Java SE 7 技術手冊投影片第 10 章 - 輸入輸出
Sql Server 高级技巧系列之一:索引详解
Oracle 資料庫檔案介紹
Oracle 資料庫建立
5, initialization & cleanup
Ad

Similar to Sql语句编写优化和基本原理总结 (20)

PPT
Sql语句的优化
PDF
My sql数据库开发的三十六条军规
PDF
MySQL数据库开发的三十六条军规
PDF
Mysql数据库开发的三十六条军规 石展_完整
PDF
诗檀软件 Oracle开发优化基础
PDF
Mysql开发与优化
PPT
Something about oracle joins
PDF
MySQL运维那些事
PPT
腾讯大讲堂48 数据库查询优化浅析
PPSX
MySQL Base Skill
DOCX
Optimizer operators
PDF
Sql语句大全大全(经典珍藏版)
PDF
Oracle&mysql数据库模式设计
PDF
资身Dba经验谈
PDF
Mysql fast share
PPSX
Mysql遇到的一些问题
PPTX
Mysql 高级优化之 逻辑处理
PDF
A.oracle 数据字典与脚本初步
PDF
MySQL InnoDB 源码实现分析(一)
DOC
Oracle数据库中大型表查询优化研究
Sql语句的优化
My sql数据库开发的三十六条军规
MySQL数据库开发的三十六条军规
Mysql数据库开发的三十六条军规 石展_完整
诗檀软件 Oracle开发优化基础
Mysql开发与优化
Something about oracle joins
MySQL运维那些事
腾讯大讲堂48 数据库查询优化浅析
MySQL Base Skill
Optimizer operators
Sql语句大全大全(经典珍藏版)
Oracle&mysql数据库模式设计
资身Dba经验谈
Mysql fast share
Mysql遇到的一些问题
Mysql 高级优化之 逻辑处理
A.oracle 数据字典与脚本初步
MySQL InnoDB 源码实现分析(一)
Oracle数据库中大型表查询优化研究
Ad

Sql语句编写优化和基本原理总结