Oracle性能调优总结

1.数据字典命中率

查询数据字典命中率: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;

2.高速缓存命中率

db block gets 从高速缓冲区命中
consistent gets 回滚段所需数据款
physical reads 从硬板读取的数据块

v$sgainfo查询db_block_buffersdb_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

索引

1. 位图索引

  1. 我们先创建一张表,这张表的特点是bitid是0或1,适宜用位图索引

    create table t as selectmod(object_id,2) bitid, object_id, object_name from dba_objects;

  2. 查看select * from t where bitid = 0的执行计划;

没建索引前:

B树索引:

位图索引:

结论:位图索引适合列值较少的。

2. B树索引

接下来我们在上面的表上查看

select * from t where object_id=99

的执行计划;

无B树索引

有B树索引

结论:B树索引适合用于唯一性较高的表上。

3. 聚簇索引表

无聚簇索引

有聚簇索引


2015年4月15日19:17:35

设置cursor_sharing

可以通过设置CURSOR_SHARING参数来指示Oracle透明地将字面量替换为绑定变量。

清空共享缓存区:

alter system flush shared_pool;

CURSOR_SHARING参数有以下几个值:

EXACT 这是默认值。不将字面量替换为绑定变量

SIMILAR只有当替换不会影响到执行计划时,才会将字面量替换为绑定变量。在有些情况下,不同的字面量值可能会对应不同的执行计划。如果优化器认为如此,将不会发生替换

FORCE 只要有可能,字面量就会被替换为绑定变量

bulk collect into

之所以可以降低逻辑读的数量,是因为批量提取通常可以发现它所需要的多条记录位于同一个数据块上。因此,批量越大,就会有越多的记录出现在已经请求过的数据块上。当批量较小时,同样的数据块需要被重复地请求。

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

排序

1. 查看排序区内存的大小以及设置;实际排序所用到的内存、磁盘的统计信息:

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 sysstatwherenamelikesort pgastat;

SQL> select name , value from v$sysstat where name like 'sort%';

NAME                                                                                                                          VALUE
-------------------------------------------------------------------------------------------------------------------------------- ----------
sorts (memory)                                                                                                                 4283
sorts (disk)                                                                                                                      0
sorts (rows)                                                                                                                  40823

2. 比较以下操作

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内存

3. 在cust_last_name创建b*索引

没建索引:

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 |
---------------------------------------------------------------------------------

可以发现在一列建立索引后,对该列进行排序操作不需要再执行排序操作,
他会根据索引来进行查询(索引中本来就已经排好序)

结论:

建立索引可以节省排序操作的时间。

4. 查询前十条记录

通常我们都会:

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行。

竟然不是刚刚那样乱的。

结论:

**建立索引能够对提高子查询的性能,并且查询前十条记录不再需要使用子查询,
因为建立好索引后已经是排好序的,只要根据索引从表中拿出前十条记录即可。**

5.分组与索引

首先先建立一个表

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

  1. 查询v$sys_time_model,字段stat_name中的值是’DB time’和’Pl/SQL execution elapsed time’对应的字段value值,它们分别是数据库访问时间与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的执行时间。

  1. 对于单独一块PL/SQL的执行时间,可以使用V$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


TEXT

RANKING

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


TEXT

RANKING

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操作,如insertupdate,

##实验:


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_TABLE_OUTPUT

Plan hash value: 1286539636


| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |

| 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 |

PLAN_TABLE_OUTPUT

| 6 | HASH GROUP BY | | Q1,00 | PCWP | |
| 7 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |

| 8 | TABLE ACCESS FULL| P_TST | Q1,00 | PCWP | |

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调优

  1. 使用create table as select 语句调优
    create table t1 as select * from dba_objects;
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连用
默认插入需要写事务日志和管理缓冲区高速缓存,所以耗时会更长

对Delete的优化:

删除一行数据的代价在感觉上可能不太明显,但是删除一行在数据库对记录执行的操作中代价最昂贵。
删除操作的一般步骤:
* 查找要删除的行
* 从数据块找到要删除的行
* 查找和删除索引中指向要删除的行的条目
* 检查参照的完整性
* 处理任意一个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_TABLE_OUTPUT

Plan hash value: 2821162943


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

| 0 | DELETE STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | DELETE | T2 | | | | |

|* 2 | INDEX RANGE SCAN| IDX | 1 | 13 | 1 (0)| 00:00:01 |

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT


2 - access(“OBJECT_ID”=1000)

Note

  • dynamic sampling used for this statement (level=2)

>
总结:
我们可以看到执行计划是不一样的,
没有索引:全表扫描
有索引:通过索引扫描,
我们可以发现建立索引对删除效果拔群!~
>

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 ,这个要看删除的条件的是怎么写的,如果条件用到索引了,会提高,没有用到,会全表扫描。 也不会提高。

你可能感兴趣的:(Oracle)