查询数据字典命中率:select 1 - sum(getmisses) / sum(gets) “data dictionary hitratio” from v$rowcache;
数据块 parameter
命中 gets
没命中 getmisses
查询数据字典命中率:select 1 - sum(getmisses) / sum(gets) “data dictionary hitratio” from v$rowcache;
设置新的 shared_pool_size
alter system set shared_pool_size = 1000m;
db block gets 从高速缓冲区命中
consistent gets 回滚段所需数据款
physical reads 从硬板读取的数据块
v$sgainfo查询db_block_buffers或db_cache_size获取数据高速缓存的大小;
查询v$sysstat获取数据库缓冲区高速缓存的使用情况;
SELECT name,value FROM V$SYSSTAT WHERE name IN (‘db block gets’,‘consistent gets’,‘physical reads’);
命中率 = 1 - physical reads/(db block gets + consistent gets)
调整db_block_buffers或db_cache_size
2015年3月11日19:06:33
查看程序运行时间:
set timing on
2015年3月18日19:23:54
RTRIM:
RTRIM ('wfrqqww', 'qq')
首先从字符串’wfrqqww’右边查找’qq’中的任意字符,此例为’q’,’q’,直到’wfrqqww’右边不为’q’和’q’字符为止,所以结果还是wfrqqww
LPAD:
lpad( string, padded_length, [ pad_string ] )
语法格式如下:
lpad( string, padded_length, [ pad_string ] )
string
准备被填充的字符串;
padded_length
填充之后的字符串长度,也就是该函数返回的字符串长度,如果这个数量比原字符串的长度要短,lpad函数将会把字符串截取成从左到右的n个字符;
pad_string
填充字符串,是个可选参数,这个字符串是要粘贴到string的左边,如果这个参数未写,lpad函数将会在string的左边粘贴空格。
lpad函数从左边对字符串使用指定的字符进行填充。从其字面意思也可以理解,l是left的简写,pad是填充的意思,所以lpad就是从左边填充的意思。
生成SQL语句执行计划:
explain plan [set statement_id='id'] [into table_name]
for sql_statement;
select * from hr.employees join hr.departments using (department_id);
查询计划表:
select rtrim (lpad ( ’ ‘, 2 * level) || rtrim (operation) || ’ ’ || object_name) query_plan, cost, cardinality
from plan_table start with id = 0 connect by prior id = parent_id;
这个是不是太麻烦了:用这个更简单的:
select * from table (dbms_xplan.display);
使用虚拟索引
select * from sh.sales where quantity_sold >1000;
alter session set "_use_nosegment_indexes" = true
Create index idx on sh.sales(quantity_sold)
NOSEGMENT;
select * from table(dbms_xplan.display(null,null,' BASIC +COST '));
2015年3月25日19:16:50
oracle建表默认采用堆表
创建堆表:此类型的表中,数据会以堆的方式进行管理,增加数据时候,会使用段中找到的第一个能放下此数据的自由空间。当从表中删除数据时候,则允许以后的UPDATE和INSERT重用这部分空间,它是以一种有些随机的方式使用。
create table t( a int, b varchar2(4000) default rpad(‘*’, 4000, ‘*’), c varchar2(3000) default rpad(‘*’, 3000,‘*’) );
验证堆表插入数据的次序。
适用于:经常修改的,不经常查询的。
就是存储在一个索引结构中的表,数据按主键进行存储和排序。
create table indexTable(
ID varchar2 (10),
NAME varchar2 (20),
constraint pk_id primary key (ID)
) organization index;
适用于:经常查询不经常修改,between等。
索引聚簇表:聚簇是指:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中;利用聚簇,一个块可能包含多个表 的数据。
创建一个索引簇:
create cluster emp_dept_cluster ( deptno number(2) );
创建一个索引聚簇表:
create table cluster_dept(
deptno number(2) primary key,
dname varchar2(14),
loc varchar2(13)) cluster emp_dept_cluster(deptno)
适用于:连接,多表查询。
SET AUTOTRACE TRACEONLY; -- 只显示执行计划,不显示结果集
2015年4月1日19:24:41
我们先创建一张表,这张表的特点是bitid是0或1,适宜用位图索引
create table t as selectmod(object_id,2) bitid, object_id, object_name from dba_objects;
查看select * from t where bitid = 0的执行计划;
结论:位图索引适合列值较少的。
接下来我们在上面的表上查看
select * from t where object_id=99
的执行计划;
无B树索引
有B树索引
结论:B树索引适合用于唯一性较高的表上。
无聚簇索引
有聚簇索引
2015年4月15日19:17:35
可以通过设置CURSOR_SHARING参数来指示Oracle透明地将字面量替换为绑定变量。
清空共享缓存区:
alter system flush shared_pool;
CURSOR_SHARING参数有以下几个值:
EXACT 这是默认值。不将字面量替换为绑定变量
SIMILAR只有当替换不会影响到执行计划时,才会将字面量替换为绑定变量。在有些情况下,不同的字面量值可能会对应不同的执行计划。如果优化器认为如此,将不会发生替换
FORCE 只要有可能,字面量就会被替换为绑定变量
之所以可以降低逻辑读的数量,是因为批量提取通常可以发现它所需要的多条记录位于同一个数据块上。因此,批量越大,就会有越多的记录出现在已经请求过的数据块上。当批量较小时,同样的数据块需要被重复地请求。
declare
type obj_id_type is table of sys.dba_objects.object_id%type index by binary_integer;
type obj_name_type is table of sys.dba_objects.object_name%type index by binary_integer;
object_id obj_id_type;
object_name obj_name_type;
begin
select object_id,object_name bulk collect into object_id,object_name from dba_objects;
end;
和
begin
for i in 1..72462 loop
execute immediate 'select object_id,object_name from dba_objects where object_id=:i' using i;
end loop;
end;
比
declare
type xtype is table of insertTest.c1%type index by binary_integer;
type ytype is table of insertTest.c2%type index by binary_integer;
xlist xtype;
ylist ytype;
begin
for i in 1 .. 100000 loop
xlist(i):=i;
ylist(i):=’This’||i;
end loop;
forall i in 1.. xlist.COUNT
insert into insertTest(c1,c2) values(xlist(i),ylist(i));
end;
2015年4月22日19:10:55
查询参数:
show parameter optimizer_m
select name,value from v$parameter where name='optimizer_mode';
查看详细的执行计划:
select * from table(dbms_xplan.display(null,null,'advanced'));
首先创建一张表:
create table t as select * from dba_objects;
创建B*索引:
create index idx_t_owner on t(owner);
执行计划:
explain plan for select * from t where owner='SYS';
查看执行计划:
select * from table(dbms_xplan.display(null,null,'advanced'));
我们发现虽然我们建了索引但oracle并没有使用索引,这是因为该列的唯一值低,即重复的值多
若使用索引效率甚至会低于全表扫描,所以oracle选择了全表扫描。
这里要注意
dynamic sampling used for this statement (level=2)
这一句话,此时,Oracle优化器应用了动态统计量收集技术(Dynamic Sampling。
在没有统计信息下oracle会使用此技术。
收集t表的统计信息:
exec dbms_stats.gather_table_stats(user,'T',cascade => true);
使用了这句语句后在执行刚才的执行计划时就会发现刚刚那句话消失了,也就是说这时oracle没有采用动态收集技术。因为已经收集了t表的统计信息了,无需再进行动态采样。
下面我们再试一下唯一值较高的,scott只有6行数据,说明此列唯一性高
explain plan for
select * from t where owner='SCOTT';
这时我们可以发现是使用了索引。
直方图的使用不受索引的限制,可以在表的任何列上构建直方图。
构造直方图最主要的原因就是帮助优化器在表中数据严重偏斜时做出更好的规划
建立直方图:
begin
dbms_stats.gather_table_stats(
ownname=>'',tabname=>'T',
estimate_percent=>dbms_stats.auto_sample_size,
method_opt=>'for columns size 10 owner',
cascade=>true,
degree=>7);
end;
其中degree指定了并行度视主机的CPU个数而定,estimate_percent指定了采样比率,此处使用了auto目的是让oracle来决定采样收集的比率,绘制直方图时会根据采样的数据分析结果来绘制,当然也可以人为指定采样比率。如:estimate_percent=>20指定采样比率为20%,cascade=>true指定收集相关表的索引的统计信息,该参数默认为false,因此使用dbms_stats 收集统计信息时默认是不收集表的索引信息的
2015年4月29日19:19:27
这次我们使用sh这个用户:
alter user sh account unlock;
alter user sh identified by sh;
grant select any table to sh;
1.我们执行一下这个语句:
explain plan for
select * from sh.customers
where cust_year_of_birth = 1976 and
cust_gender='M' and
cust_marital_status='single';
下面我们使用一下提示:
explain plan for
select /*+ FULL(customers) */ * from sh.customers
where cust_year_of_birth = 1976 and
cust_gender='M' and
cust_marital_status='single';
当你想要改变语句的执行计划时,可以使用提示对优化器进行引导。
2.再看看这个例子:
explain plan for
select employee_id,first_name,last_name
from hr.employees where manager_id=100
and department_id=90
下面我们使用一下提示:
explain plan for
select /*+ index(e emp_manager_ix) */ employee_id,first_name,last_name
from hr.employees where manager_id=100
and department_id=90
1.首先对用户进行授权:
grant create any sql profile to sh;
grant drop any sql profile to sh;
grant alter any sql profile to sh;
2.创建摘要:
SELECT /* sises */ * FROM customers
JOIN countries USING (country_id)
WHERE cust_marital_status = 'Mar-AF' AND country_name = 'United States of America'
AND cust_year_of_birth > 1960
使用调优包创建调优任务:
VAR v_sql_id VARCHAR2(13)
VAR v_task_name VARCHAR2
begin
select sql_id
into :v_sql_id
from v$sql
where sql_text like 'SELECT /* sises%';
end;
2015年5月13日19:06:29
create table segs as select * from dba_segments where owner=’SYS’;
create table objs as select * from dba_objects where owner=’SYS’;
set autotrace on
exec dbms_stats.gather_table_stats(user,’SEGS’,cascade=>true);
exec dbms_stats.gather_table_stats(user,’OBJS’,cascade=>true);
dbms_stats.delete_table_stats
consistent gets 读多少个数据块
2015年5月20日19:14:43
pga_aggregate_target:此参数用来指定所有session总计可以使用最大PGA内存 olap:50% oltp:20%
SQL> show parameter pga_aggre
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
pga_aggregate_target big integer 0
SQL> show parameter workarea_size_policy
workarea_size_policy:此参数用于开关PGA内存自动管理功能 auto:自动分配sort_area_size 属于workarea 如果需要经常排序就需要把这个值设置大点
SQL> show parameter workarea_size_policy
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
workarea_size_policy string AUTO
select name, value from v sysstatwherenamelike‘sort pgastat;
SQL> select name , value from v$sysstat where name like 'sort%';
NAME VALUE
-------------------------------------------------------------------------------------------------------------------------------- ----------
sorts (memory) 4283
sorts (disk) 0
sorts (rows) 40823
select * from customers;
SQL> set autotrace traceonly
SQL> select * from customers;
已选择55500行。
已用时间: 00: 00: 01.93
执行计划
----------------------------------------------------------
Plan hash value: 2008213504
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55500 | 9810K| 406 (1)| 00:00:05 |
| 1 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 9810K| 406 (1)| 00:00:05 |
-------------------------------------------------------------------------------
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
5057 consistent gets
1455 physical reads
0 redo size
10855625 bytes sent via SQL*Net to client
41109 bytes received via SQL*Net from client
3701 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
55500 rows processed
select * from customers order by cust_last_name;
SQL> select * from customers order by cust_last_name;
已选择55500行。
已用时间: 00: 00: 01.93
执行计划
----------------------------------------------------------
Plan hash value: 2792773903
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55500 | 9810K| | 2612 (1)| 00:00:32 |
| 1 | SORT ORDER BY | | 55500 | 9810K| 12M| 2612 (1)| 00:00:32 |
| 2 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 9810K| | 406 (1)| 00:00:05 |
----------------------------------------------------------------------------------------
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
1459 consistent gets
1454 physical reads
0 redo size
6278979 bytes sent via SQL*Net to client
41109 bytes received via SQL*Net from client
3701 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
55500 rows processed
可以看到使用order by
用到了额外的12M内存
没建索引:
explain plan for select cust_last_name from customers order by cust_last_name;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------
Plan hash value: 2792773903
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55500 | 433K| | 610 (1)| 00:00:08 |
| 1 | SORT ORDER BY | | 55500 | 433K| 880K| 610 (1)| 00:00:08 |
| 2 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 433K| | 405 (1)| 00:00:05 |
----------------------------------------------------------------------------------------
建立索引:
create index lastname_idx on customers(cust_last_name);
explain plan for select /*+ index(c lastname_idx) */ cust_last_name from customers order by cust_last_name;
执行计划:
SQL> explain plan for select /*+ index(c lastname_idx) */ cust_last_name from customers order by cust_last_name;
已解释。
已用时间: 00: 00: 00.00
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------
Plan hash value: 3470560620
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55500 | 433K| 143 (1)| 00:00:02 |
| 1 | INDEX FULL SCAN | LASTNAME_IDX | 55500 | 433K| 143 (1)| 00:00:02 |
---------------------------------------------------------------------------------
可以发现在一列建立索引后,对该列进行排序操作不需要再执行排序操作,
他会根据索引来进行查询(索引中本来就已经排好序)
建立索引可以节省排序操作的时间。
通常我们都会:
select cust_last_name from customers where rownum<=20 order by 1;
SQL> select cust_last_name from customers where rownum<=20 order by 1;
CUST_LAST_NAME
--------------------------------------------------------------------------------
Everett
Everett
Everett
Everett
Everett
Everett
Everett
Everett
Everett
Ruddy
Ruddy
CUST_LAST_NAME
--------------------------------------------------------------------------------
Ruddy
Ruddy
Ruddy
Ruddy
Ruddy
Ruddy
Ruddy
Ruddy
Ruddy
已选择20行。
这样是错误的,因为在oracle中where永远都是先执行的也就先取20条再排序。
正确的做法是使用子查询:
select cust_last_name from (select * from customers order by cust_last_name) where rownum<10;
SQL>select cust_last_name from (select * from customers order by cust_last_name) where rownum<10;
CUST_LAST_NAME
--------------------------------------------------------------------------------
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
CUST_LAST_NAME
--------------------------------------------------------------------------------
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
已选择20行。
没建索引:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------
Plan hash value: 1285511559
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 198 | | 2612 (1)| 00:00:32 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | VIEW | | 55500 | 1192K| | 2612 (1)| 00:00:32 |
|* 3 | SORT ORDER BY STOPKEY| | 55500 | 9810K| 12M| 2612 (1)| 00:00:32 |
| 4 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 9810K| | 406 (1)| 00:00:05 |
---------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
3 - filter(ROWNUM<10)
已选择17行。
建立索引后:
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 3026242074
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 198 | 4 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 9 | 198 | 4 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN| LASTNAME_IDX | 9 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
已选择15行。
建立索引后,子查询效率明显提高
同时select cust_last_name from customers where rownum<=10 order by cust_last_name;
和上面的结果已经大不相同。
SQL> select cust_last_name from customers where rownum<=10 order by cust_last_name;
CUST_LAST_NAME
--------------------------------------------------------------------------------
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
Aaron
已选择10行。
执行计划:
SQL> explain plan for
2 select cust_last_name from customers where rownum<=10 order by cust_last_name;
已解释。
已用时间: 00: 00: 00.00
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------
Plan hash value: 2820001957
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------
---------------------------------------------------
1 - filter(ROWNUM<=10)
已选择14行。
竟然不是刚刚那样乱的。
**建立索引能够对提高子查询的性能,并且查询前十条记录不再需要使用子查询,
因为建立好索引后已经是排好序的,只要根据索引从表中拿出前十条记录即可。**
首先先建立一个表
SQL> create table s as select * from sales;
表已创建。
s表与sales表的数据完全是一致的但s表没有sales表上的索引。
然后我们看一下执行计划:
SQL> explain plan for
2 select cust_id,avg(amount_sold) from s group by cust_id;
已解释。
已用时间: 00: 00: 00.23
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
Plan hash value: 1912481676
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 785K| 19M| 1271 (4)| 00:00:16 |
| 1 | HASH GROUP BY | | 785K| 19M| 1271 (4)| 00:00:16 |
| 2 | TABLE ACCESS FULL| S | 785K| 19M| 1236 (1)| 00:00:15 |
---------------------------------------------------------------------------
Note
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
-----
- dynamic sampling used for this statement (level=2)
已选择13行。
我们再看一下sales表(即建立了索引的表):
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 2820001957
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
---------------------------------------------------
1 - filter(ROWNUM<=10)
已选择14行。
group by
的一列上建立索引group by 性能更佳。
下面是关于order by 升序降序的执行计划可以看出建立索引升降序对排序不会影响性能
升序:
SQL> select cust_last_name from customers where rownum <= 10 order by cust_last_name;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 2820001957
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
---------------------------------------------------
1 - filter(ROWNUM<=10)
已选择14行。
降序:
SQL> select cust_last_name from customers where rownum <= 10 order by cust_last_name;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------
Plan hash value: 1596600344
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 72 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | INDEX FULL SCAN DESCENDING| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------
---------------------------------------------------
1 - filter(ROWNUM<10)
已选择14行。
2015年5月27日19:05:02
调优PL/SQL
该视图v$sys_time_model
select stat_name , sum(value) from v$sys_time_model
where stat_name in ('DB_TIME','PL/SQL execution elapsed time')
group by stat_name;
结果:
STAT_NAME SUM(VALUE)
-------------------------------------------------------------------------------------------------------------------------------- ----------
PL/SQL execution elapsed time 74466
查出来的结果是PL/SQL的执行时间。
PLSQL_EXEC_TIME
大于0就是对于的SQL语句中包含PL/SQL的执行时间,而ELAPSED_TIME
是SQL的执行时间。select sql_id,plsql_exec_time,elapsed_time from v$sql
where plsql_exec_time>0;
结果:
SQL_ID PLSQL_EXEC_TIME ELAPSED_TIME
-------------------------- --------------- ------------
cfnrd41661bgr 48311 736289
a6u3yjca29nqc 65 56924
c8pktxyw9kfd8 26119 333771
3.DBMS_PROFILER
先运行:
@ D:\app\student\product\11.2.0\dbhome_1\RDBMS\ADMIN\profload.sql
@ D:\app\student\product\11.2.0\dbhome_1\RDBMS\ADMIN\proftab.sql
create or replace procedure test is
v_count number;
begin
select count(*) into v_count from dba_objects;
for i in 1..v_count loop
execute immediate 'select * from objs where object_id='||i;
exit when v_count=50;
end loop;
end;
/
declare
returncode binary_integer;
begin
returncode := dbms_profiler.start_profiler('profiler demo');
test;
returncode := dbms_profiler.stop_profiler;
dbms_output.put_line('return code is'||returncode);
commit;
end;
使用DBMS_PROFILER侦测PL/SQL中最消耗资源、成本较大的代码行:
with plsqry as(
select u.unit_name ,line#,d.total_time,substr(s.text,1,40) as text,
dense_rank() over(order by d.total_time desc) ranking
from plsql_profiler_runs r join plsql_profiler_units u using(runid)
join plsql_profiler_data d using(runid,unit_number)
left join all_source s on(s.owner=u.unit_owner and s.type=u.unit_type
and s.name=u.unit_name and s.line=d.line#) where r.run_comment='profiler demo'
)
select * from plsqry where ranking <=3 order by ranking
/
UNIT_NAME LINE# TOTAL_TIME
TEST 4 123548516
select count(*) into v_count from dba_ob
1
TEST 6 1112819
execute immediate ‘select * from objs wh
2
UNIT_NAME LINE# TOTAL_TIME
20 83748
3
--------------------
2015年6月3日19:01:42
并发
可用show parameter查看
parallel_min_servers :
当Oracle 数据库启动的时候,实例会根据初始化参数: PARALLEL_MIN_SERVERS=M的值来在并行子进程池中预先分配M个并行服务进程,当一条SQL 被CBO判断为需要并行执行时发出SQL的会话进程变成并行协助进程,它按照并行执行度的值来分配进程服务器进程。
parallel_max_servers:该池并行服务进程的最大值数量。
并发适合:时间长的任务,OLAP
若一个CPU不适合并发进程。
原因:并发还需要产生一个协调进程
并行处理的应用场景,适合用于长时间、批量处理的SQL操作,特别是属于OLAP系统应用。
1.Parallel Query(并行查询)
2.Parallel DDL(并行DDL操作,如建表,建索引等)
3.Parallel DML(并行DML操作,如insert,update,
##实验:
1.创建表:
```sql
create table p_tst asselect * from hr.employees;
2.查询:
explain plan for select sum(salary) from p_tst group by department_id;
使用并发:explain plan for select /*+ parallel(p_tst,2)*/ sum(salary) from p_tst group by department_id;
3.结果:
未使用并发:
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
Plan hash value: 1390189472
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 107 | 2782 | 3 (34)| 00:00:01 |
| 1 | HASH GROUP BY | | 107 | 2782 | 3 (34)| 00:00:01 |
| 2 | TABLE ACCESS FULL| P_TST | 107 | 2782 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
Note
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
-----
- dynamic sampling used for this statement (level=2)
使用并发:
select * from table(dbms_xplan.display(null,null,'basic parallel'));
Plan hash value: 1286539636
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | Q1,01 | PCWP | |
| 4 | PX RECEIVE | | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH |
| 6 | HASH GROUP BY | | Q1,00 | PCWP | |
| 7 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
Px block iterator :这个操作通常处于并行管道的第一步,它把表分成多个块,每个块由涉及并行处理服务器进程中的一个并行处理
Px send 表明数据从一个并行进程发送到另外一个并行进程。
Px receive 这是给并行查询协调进程一个接收操作。
Px send qc 这是给并行查询协调进程一个发送操作。
Px coordinator这个步骤表明并行查询协调进程正从并行流接收数据并返回给SQL语句。
当使用了并行执行,SQL的执行计划中就会多出一列:in-out。 该列帮助我们理解数据流的执行方法。 它的一些值的含义如下:
Parallel to Serial(P->S): 表示一个并行操作发送数据给一个串行操作,通常是并行进程将数据发送给并行调度进程。
Parallel to Parallel(P->P):表示一个并行操作向另一个并行操作发送数据,经常是两个从属进程之间的数据交流。
Parallel Combined with parent(PCWP): 同一个从属进程执行的并行操作,同时父操作也是并行的。
Parallel Combined with Child(PCWC): 同一个从属进程执行的并行操作,子操作也是并行的。
2015年6月10日19:03:24
DML调优
SQL> create table t2 as select * from dba_objects;
表已创建。
已用时间: 00: 00: 00.84
使用直接IO调优:
SQL> create /*+ append */ table t3 as select * from dba_objects;
表已创建。
已用时间: 00: 00: 00.76
SQL> create table t4 as select * from dba_objects where 1=2;
表已创建。
已用时间: 00: 00: 00.03
SQL> insert into t4 select * from dba_objects;
已创建72465行。
已用时间: 00: 00: 01.06
SQL> create /*+ parallel append */ table t5 as select * from dba_objects;
表已创建。
已用时间: 00: 00: 01.09
结果竟然发现并行+直接插入时间最长,这是因为机器的配置吧。
在默认或常规模式的插入操作中,在创建新数据块之前,Oracle会尝试把行数据插入到有空余容量的数据块中。新块或被修改的块会在内存(缓冲区高速缓存)中被处理,之后由数据库写进程写入磁盘(数据文件)。
直接IO插入可以减少缓冲区高速缓存的管理和减少重做日志IO的相关开销来提高性能,他是直接写入到数据库文件。
使用直接插入有一定的限制,表不能是聚镞类或者不能包含对象类型,而且在直接路径插入后,在同一事务中,不能有其它SQL对表进行读或修改。
总结:
常规模式:插入->缓冲区高速缓存->DBWR->数据库文件
直接IO: 插入->数据库文件
使用直接IO一般和create table as select连用
默认插入需要写事务日志和管理缓冲区高速缓存,所以耗时会更长
删除一行数据的代价在感觉上可能不太明显,但是删除一行在数据库对记录执行的操作中代价最昂贵。
删除操作的一般步骤:
* 查找要删除的行
* 从数据块找到要删除的行
* 查找和删除索引中指向要删除的行的条目
* 检查参照的完整性
* 处理任意一个on delete 触发器
* 为以上所有变更创建ROLLBACK条目
所以特别强调DELETE的优化!!!
对于Delete,我们可以在第一步做文章:
建立索引,让他更快找到要删除的行
例子:
SQL> delete from t1 where object_id=1000;
已删除 1 行。
已用时间: 00: 00: 00.21
SQL> create index idx on t2(object_id);
索引已创建。
已用时间: 00: 00: 00.17
SQL> delete from t2 where object_id=1000;
已删除 1 行。
已用时间: 00: 00: 00.01
无索引:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
Plan hash value: 775918519
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 11 | 143 | 282 (1)| 00:00:04 |
| 1 | DELETE | T1 | | | | |
|* 2 | TABLE ACCESS FULL| T1 | 11 | 143 | 282 (1)| 00:00:04 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
---------------------------------------------------
2 - filter("OBJECT_ID"=1000)
Note
-----
- dynamic sampling used for this statement (level=2)
有索引:
Plan hash value: 2821162943
| 0 | DELETE STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | DELETE | T2 | | | | |
Predicate Information (identified by operation id):
2 - access(“OBJECT_ID”=1000)
>
总结:
我们可以看到执行计划是不一样的,
没有索引:全表扫描
有索引:通过索引扫描,
我们可以发现建立索引对删除效果拔群!~
>
delete删除的数据可恢复 truncate是ddl语句,没有事务,无法恢复
Update:
无索引:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2927627013
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 11 | 143 | 282 (1)| 00:00:04 |
| 1 | UPDATE | T1 | | | | |
|* 2 | TABLE ACCESS FULL| T1 | 11 | 143 | 282 (1)| 00:00:04 |
---------------------------------------------------------------------------
有索引:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
Plan hash value: 212215341
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | UPDATE | T2 | | | | |
|* 2 | INDEX RANGE SCAN| IDX | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------
索引对DML操作的影响:
insert 不会提高,insert 用不到索引,只会增加维护索引的时间。
update ,更新索引列不会提高,少量更新非索引列,会有提高 ; 更新索引列,索引要重新维护,更新非索引列,倒是没什么影响 。
delete ,这个要看删除的条件的是怎么写的,如果条件用到索引了,会提高,没有用到,会全表扫描。 也不会提高。