Oracle SQL 语句优化
来源:互联网 发布:unity3d角色换衣 编辑:程序博客网 时间:2024/05/10 03:49
1.前言
日常工作中我们常遇到各种与数据库有关的问题,我处理的案例中,尤以ORACLE语句优化居多,说明语句优化在电信计费系统中较常见。任何工作都有章可循,语句优化也不例外。现结合实践整出优化思路与大家分享。
2.优化步骤总结
2.1找到需要调优的SQL语句
查看等待事件是找出需调优语句的极好办法。
2.2查看其执行计划
了解SQL运行方式,如全表读、索引读、HASH连接、分区扫描等,还可看出大致代价及物理读逻辑读。
2.3检查表和索引的分析情况
检查关键谓词是否有索引,及表和索引是否有分析过。
2.4检查表内部块的情况
检测是否存在行迁移及高水平位问题,目的是为了避免访问过多不必要的块。
2.5减少IO
有时由于涉及的表记录太大,以上的优化还不能达到要求,可考虑如下几个方案来减少IO。
2.5.1 cache表和索引
将表和索引CACHE到内存KEEP区中,将物理IO降低到0。
2.5.2重新组织表结构
取部分有用字段,且物理的将表进行排序,从而充分提高索引的效率,或者考虑索引组织表、族。
2.5.3考虑能否不回表操作
2.6改写sql
以上步骤还不能满足要求,可考虑其他方式:如将自连接改为分析函数、利用分区特性、利用ROWID和ROWNUM特性、利用中间表转化、利用物化视图等,这些因为需改写SQL显的更复杂。但在我的sql优化经历中,一般前5步做完后就收效甚佳,改动代码进一步优化的案例并不多见。
以上是在工作中总结出SQL优化步骤,让我们从一个案例来说说如何利用以上思路进行调优。
3.案例背景
在计费泉州上线准备期间,割接组同事希望提升工程环境中一存储过程的执行速度,当时大致12小时跑完数据。该存储过程用途是生成将来泉州上线数据的中间表,进而将中间表迁移到生产库,最终完成泉州数据迁移。此步骤执行太长将影响泉州割接上线。
4.案例处理
首先想到定位该存储过程在执行中哪出现瓶颈?我从数据库等待事件入手分析,因为只要SQL语句在执行,未结束就有等待,而且还有等待时长可协助判断。
4.1首先获取等待事件信息及SQL语句
执行如下脚本查询数据库目前的非空闲等待及其他详细信息:
select 'kill -9 ' || pr.spid || ';',
'alter system kill session ' || '''' || s.sid || ',' || s.serial# || '''' || ';',
s.username,s.serial#,s.machine,s.status,pr.spid,sw.*,sq.sql_text,sq.address
from v$session s, v$session_wait sw, v$process pr, v$sqlarea sq
where s.username is not null and sw.sid = s.sid and s.paddr = pr.ADDR
and (s.sql_hash_value = sq.hash_value or s.prev_hash_value = sq.hash_value)
and (s.sql_address = sq.address or s.prev_sql_addr = sq.address) and sw.event not like '%SQL*Net%'
order by s.username;
执行以上脚本,结合机器名及SQL字段,定位出该过程的SID=28,为查看详细语句,执行如下脚本:
SELECT sql_text FROM v$sqltext a
WHERE (a.hash_value, a.address) IN (
SELECT DECODE (sql_hash_value,0, prev_hash_value,sql_hash_value ),
DECODE (sql_hash_value, 0, prev_sql_addr, sql_address)
FROM v$session b WHERE b.sid= '&sid')
ORDER BY piece ASC
发现代入sid查询,每次跟踪到的都是如下两条语句
语句1:
select a.PROD_ID,a.prod_spec_id,b.mdse_spec_id, decode(c.region_id, null, 59501, c.region_id) region_id,a.pay_type,a.EXCH_ID
from prod_his_crm_qz a, mdse_his_crm_qz b, manage_region_ibssf c
where a.prod_id = b.prod_id and a.region = c.region_code(+) and a.prod_id = 20000
and b.mdse_type in ('101', '107', '108') and a.attr_sort <> '101'
and a.state NOT in ('70N', '70R') and b.state NOT in ('70N', '70R');
语句2:
select MAX(AGREEMENT_CODE) from t_v_telecom_account2_qz where tel_acct_id = v_n_acct_id;
这两个语句反复在等待事件中出现,说明该过程这两个语句有明显等待出现,可重点关注。
找到问题SQL,从优化和处理问题的角度来说是向成功迈进了一大步,让我们继续进行如下:
4.2获取需优化语句的执行计划
首先分析语句1的执行计划
SQL> explain plan for 将语句1代入此处(略去该语句)
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 89 | 21381 |
|* 1 | HASH JOIN OUTER | | 1 | 89 | 21381 |
| 2 | MERGE JOIN CARTESIAN| | 1 | 70 | 21373 |
|* 3 | TABLE ACCESS FULL | PROD_HIS_CRM_QZ | 1 | 43 | 12479 |
| 4 | BUFFER SORT | | 1 | 27 | 8894 |
|* 5 | TABLE ACCESS FULL | MDSE_HIS_CRM_QZ | 1 | 27 | 8894 |
| 6 | TABLE ACCESS FULL | MANAGE_REGION_IBSSF| 6174 | 114K| 7 |
Statistics
1808 recursive calls
0 db block gets
631 consistent gets
766 physical reads
0 redo size
2216 bytes sent via SQL*Net to client
666 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client