识别低效率的SQL语句
1.返回行与逻辑读的比率
CREATE TABLE t as select * from dba_objects;
--CREATE INDEX idx ON t (object_id); ---例1
alter session set statistics_level=all; set linesize 1000
set pagesize 2000
select * from t where object_id=6; SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last')); PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
SQL_ID 8cxbzma1az713, child number 0
-------------------------------------
select * from t where object_id=6 Plan hash value: 1601196873
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.07 | 1048 | 774 |
|* 1 | TABLE ACCESS FULL| T | 1 | 12 | 1 |00:00:00.07 | 1048 | 774 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=6)
Note
-----
- dynamic sampling used for this statement (level=2)
上面的语句只返回了1行数据却产生了1048个逻辑读。
执行计划显示的是全表扫描,创建索引
CREATE INDEX idx ON t (object_id); 执行计划如下:
select * from t where object_id=6 Plan hash value: 2770274160 ----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 1 | 1 |00:00:00.01 | 4 |
|* 2 | INDEX RANGE SCAN | IDX | 1 | 1 | 1 |00:00:00.01 | 3 |
----------------------------------------------------------------------------------------------
逻辑读为4。
2.执行计划中的评估是否准确。
查看e-rows 预估数量,a-rows 实际返回的数量。如果相差过大则说明需要收集表的统计信息。
SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last'));
3.类型转换需要关注。
举例如下:
create table t_col_type(id varchar2(20),col2 varchar2(20),col3 varchar2(20));
insert into t_col_type select rownum,'abc','efg' from dual connect by level<=10000;
commit;
create index idx_id on t_col_type(id);
注意ID的数据类型为VARCHAR(20)
select * from t_col_type where id=6;
执行计划
----------------------------------------------------------
Plan hash value: 3191204463
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 36 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T_COL_TYPE | 1 | 36 | 9 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("ID")=6)
注意这里没有使用到索引。
执行
select * from t_col_type where id='';
执行计划
----------------------------------------------------------
Plan hash value: 3998173245
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 36 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_COL_TYPE | 1 | 36 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_ID | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"='6')
使用到了索引。
4.小心递归调用。
6种获取执行计划的方法中,只有 autotrace 的方式可以看出递归调用的次数(recursive calls)
注意SQL中尽量不要使用函数的使用例如:
drop table people purge;
create table people (first_name varchar2(200),last_name varchar2(200),sex_id number); create table sex (name varchar2(20), sex_id number);
insert into people (first_name,last_name,sex_id) select object_name,object_type,1 from dba_objects;
insert into sex (name,sex_id) values ('男',1);
insert into sex (name,sex_id) values ('女',2);
insert into sex (name,sex_id) values ('不详',3);
commit; create or replace function get_sex_name(p_id sex.sex_id%type) return sex.name%type is
v_name sex.name%type;
begin
select name
into v_name
from sex
where sex_id=p_id;
return v_name;
end;
/
执行:
set linesize 1000
set pagesize 2000 set autotrace traceonly --例1: select sex_id,
first_name||' '||last_name full_name,
get_sex_name(sex_id) gender
from people;
执行计划如下:
----------------------------------------------------------
Plan hash value: 2528372185
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 80635 | 16M| 137 (1)| 00:00:02 |
| 1 | TABLE ACCESS FULL| PEOPLE | 80635 | 16M| 137 (1)| 00:00:02 |
----------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2) 统计信息
----------------------------------------------------------
73121 recursive calls
0 db block gets
517142 consistent gets
0 physical reads
0 redo size
3382143 bytes sent via SQL*Net to client
54029 bytes received via SQL*Net from client
4876 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
73121 rows processed
产生了73121此递归调用。
消除办法,直接使用关联查询。
5.表的访问次数。
6种获取执行计划的方法中,只有 statisitcs_level=all 的方式可以看出表访问次数(STARTS),这个很重要!
执行:
SELECT /*+ gather_plan_statistics */ count(t2.col2)
FROM t1 ,t2 WHERE t1.id=t2.id and t1.col1 = 666;
SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID g048suxnxkxyr, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics */ count(t2.col2) FROM t1 ,t2 WHERE
t1.id=t2.id and t1.col1 = 666 Plan hash value: 3711554156
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.30 | 94651 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.30 | 94651 |
| 2 | NESTED LOOPS | | 1 | | 75808 |00:00:00.31 | 94651 |
| 3 | NESTED LOOPS | | 1 | 32 | 75808 |00:00:00.19 | 18843 |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 32 | 80016 |00:00:00.08 | 1771 |
|* 5 | INDEX RANGE SCAN | T1_COL1 | 1 | 32 | 80016 |00:00:00.03 | 169 |
|* 6 | INDEX UNIQUE SCAN | T2_PK | 80016 | 1 | 75808 |00:00:00.08 | 17072 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | 75808 | 1 | 75808 |00:00:00.08 | 75808 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("T1"."COL1"=666)
6 - access("T1"."ID"="T2"."ID")
这里表的访问次数过大,应该走hash或排序合并连接,原因是表的收集信息不准确。
NL连接表的访问次数不会这么大。
6.注意表的真实访问行数。
数据准备:
drop table t1 cascade constraints;
create table t1 as select * from dba_objects;
drop table t2 cascade constraints;
create table t2 (id1,id2) as
select rownum ,rownum+100 from dual connect by level <=1000; alter session set statistics_level=all;
set linesize 1000
set pagesize 2000
优化前执行如下:
select *
from (select t1.*, rownum as rn from t1, t2 where t1.object_id = t2.id1) a
where a.rn >= 1
and a.rn <= 10;
SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last')); SQL_ID ayzfn8k0j3sms, child number 0
-------------------------------------
select * from (select t1.*, rownum as rn from t1, t2 where
t1.object_id = t2.id1) a where a.rn >= 1 and a.rn <= 10 Plan hash value: 3062220019
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.11 | 1052 | 749 | | | |
|* 1 | VIEW | | 1 | 1008 | 10 |00:00:00.11 | 1052 | 749 | | | |
| 2 | COUNT | | 1 | | 943 |00:00:00.11 | 1052 | 749 | | | |
|* 3 | HASH JOIN | | 1 | 1008 | 943 |00:00:00.11 | 1052 | 749 | 1036K| 1036K| 1197K (0)|
| 4 | TABLE ACCESS FULL| T2 | 1 | 1000 | 1000 |00:00:00.01 | 4 | 0 | | | |
| 5 | TABLE ACCESS FULL| T1 | 1 | 70183 | 73156 |00:00:00.08 | 1048 | 749 | | | |
---------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("A"."RN"<=10 AND "A"."RN">=1))
3 - access("T1"."OBJECT_ID"="T2"."ID1")
Note
-----
- dynamic sampling used for this statement (level=2)
这个查询总共返回10记录,但是内部查询返回了 条记录。
优化后:
select *
from (select t1.*, rownum as rn from t1, t2 where t1.object_id = t2.id1 and rownum<=10) a
where a.rn >= 1; SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------
SQL_ID 7wzvqay91x14y, child number 0
-------------------------------------
select * from (select t1.*, rownum as rn from t1, t2 where
t1.object_id = t2.id1 and rownum<=10) a where a.rn >= 1 Plan hash value: 1802812661
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 9 | | | |
|* 1 | VIEW | | 1 | 10 | 10 |00:00:00.01 | 9 | | | |
|* 2 | COUNT STOPKEY | | 1 | | 10 |00:00:00.01 | 9 | | | |
|* 3 | HASH JOIN | | 1 | 1008 | 10 |00:00:00.01 | 9 | 1036K| 1036K| 1210K (0)|
| 4 | TABLE ACCESS FULL| T2 | 1 | 1000 | 1000 |00:00:00.01 | 4 | | | |
| 5 | TABLE ACCESS FULL| T1 | 1 | 70183 | 10 |00:00:00.01 | 5 | | | |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A"."RN">=1)
2 - filter(ROWNUM<=10)
3 - access("T1"."OBJECT_ID"="T2"."ID1")
Note
-----
- dynamic sampling used for this statement (level=2)
T1表只返回十条数据。
这种修改 可以优化分页数据。
第一页
select *
from (select t1.*, rownum as rn from t1, t2 where t1.object_id = t2.id1 and rownum<=10) a
where a.rn >= 1; 第二页 select *
from (select t1.*, rownum as rn from t1, t2 where t1.object_id = t2.id1 and rownum<=20) a
where a.rn >= 10; 第三页 select *
from (select t1.*, rownum as rn from t1, t2 where t1.object_id = t2.id1 and rownum<=30) a
where a.rn >= 20;
这样,可以提高前几页的分页效率。
7.使用索引消除排序。
比如需要根据object_id 进行排序,那么可以使用索引消除排序操作,因为索引本身有序。
create index idx_object_id on t(object_id);
set autotrace traceonly
select * from t where object_id>2 order by object_id;
识别低效率的SQL语句的更多相关文章
- oracle 识别’低效执行’的SQL语句
用下列SQL工具找出低效SQL: SELECT EXECUTIONS , DISK_READS, BUFFER_GETS, ROUND((BUFFER_GETS-DISK_READS)/BUFFER_ ...
- 小贝_mysql sql语句优化过程
sql语句优化 一.SQL优化的一般步骤 (1).通过show status命令了解各种SQL的运行频率. (2).定位运行效率较低的SQL语句-(重点select) (3).通过explain分析低 ...
- Mysql写出高质量的sql语句的几点建议
CleverCode在实际的工作也写过一些低效率的sql语句.这些语句会给数据库带来非常大的压力.最基本的表现就是sql语句执行慢,后来逐渐的去优化和尝试. 总结了一些高质量的sql语句的写法.这里C ...
- sql语句优化SQL Server
MS SQL Server查询优化方法查询速度慢的原因很多,常见如下几种 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了 ...
- 数据库性能优化之SQL语句优化
一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的编写等是体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统 ...
- 整理:sql语句优化之SQL Server
. 增加服务器CPU个数;但是必须明白并行处理串行处理更需要资源例如内存.使用并行还是串行程是MsSQL自动评估选择的.单个任务分解成多个任务,就可 以在处理器上运行.例如耽搁查询的排序.连接.扫描和 ...
- 数据库 SQL语句优化
温馨提示:本篇内容均来自网上,本人只做了稍微处理,未进行细致研究,仅当做以后不备之需,如若你喜欢可尽情转走. 一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图 ...
- [转]数据库性能优化之SQL语句优化1
一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统 ...
- 数据库优化之SQL语句优化-记录
1. 操作符优化 (a) IN 操作符 从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别: ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查 ...
随机推荐
- FLASH CC 2015 CANVAS (三) flash中写JS调用html中JS的函数,变量
注意 此贴 为个人边“开荒”边写,所以不保证就是最佳做法,也难免有错误! 正式教程会在后续开始更新 首先我们在HTML里的JS里面添加几行代码 我们在FLASH中新建一个元件,并拖入到舞台,在属性面板 ...
- 转载java源代码阅读方法
刚才在论坛不经意间,看到有关源码阅读的),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧,如果你从来没有学过Java,或是任何一门编程语言 ...
- Linux_常用命令_03_磁盘/挂载_信息查看
1. 1.1. mount 不带参数的话,显示的是 当前已经挂载的情况 1.2. df 不带参数的话,硬盘分区状况查询 2. 2.1. cat /proc/partitions 2.2. fdisk ...
- Android_安装GooglePlay
百度搜索:“google play 安装” http://jingyan.baidu.com/article/cbf0e500f4645b2eab28935a.html http://samsungb ...
- 遮罩、警告框/弹框 - EasyUI
1.遮罩 1.1. $.messager.progress //开启遮罩 $.messager.progress({}); 或 $.messager.progress({ title: 'Please ...
- request is not finfished yet!
在项目测试的时候发现一个问题.当数据量特别多的时候,我一次性查询几万条数据的时候,就会出现很卡很慢的状态. 我把sql优化了,但是出现同样的问题.我要从后台得到数据显示在页面上来.就需要知道是查询慢, ...
- vim 学习记录2
当前行进行替换:s/XXX/YYY/gXXX是需要替换的字符串,YYY是替换后的字符串. 全局替换:% s/XXX/YYY/g. 对指定部分进行替换用V进入visual模式,再进行:s/XXX/YYY ...
- mysql命令行登录指定编码
mysql --default-character-set=utf8 -uroot -p mysql --default-character-set-utf8 -uroot-p
- list转datatable c#
private DataTable ToDataTable<T>(List<T> items) { var tb = new DataTable(typeof(T).Name) ...
- SSH2 架构常用注解
1. @Repository 将 DAO 类声明为 Bean 2.@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次. 3.@Service 通常作用在业务层 ...