数据库我爱编程框架建设收集

oracle数据库优化实验手册

2016-05-22  本文已影响495人  suzhenlin2024

oracle数据库优化


实验一:oracle安装与环境准备

一、oracle 11g安装

操作系统:windows XP/windows 7

版本:oracle 11g

http://pan.baidu.com/s/1gd9w4rp

二、oracle 11g环境配置

将OracleDBConsoleXX,OracleJobSchedulerXX,XXTNSListener和OracleServiceXX设为手动。当需要时,再手动启用。

创建新用户,便于实验的开展。如果是实验数据库,不影响其他用户使用,当然也可以使用sys用户。

sql> create user gmcc identified by gmcc;
sql> grant connect,dba to gmcc;

设置SQL*plus (oracle 11g后autotrace无需安装)

sql> set autotrace on

三、建立实验用表

建立一个BIG_TABLE用于整个过程的实验。表通过all_objects这张表生成。为了在实验中更好的验证,建议大家在这个表中的数据达到100万-500万。数量级接近我们地市客户数量。

create table big_table
as
select rownum id, a.* from all_objects a 
where 1=0;

设置为nologging,用以提高性能。

alter table big_table nologging;

输入参数1为希望的行数,往表中多次插入数据, 直到数据至少几百万行:

declare
    l_cnt number;
    l_rows number:=&1;
begin
    insert /*+ append */ into big_table
    select rownum, a.* from all_objects a 
    where rownum <= l_rows;

    l_cnt :=sql%rowcount;
    commit;

    while(l_cnt < l_rows)
    loop
        insert /*+ append */ into big_table
        select rownum+l_cnt, OWNER, OBJECT_NAME, SUBOBJECT_NAME, 
        OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, 
        STATUS, TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME
        from big_table
        where rownum <= l_rows - l_cnt;
        l_cnt:=l_cnt+sql%rowcount;
        commit;
    end loop;
end;
/

最后增加关键字的约束,同时做一下表的统计。

alter table big_table add constraint
big_table_pk primary key(id);

exec dbms_stats.gather_table_stats(user, 'BIG_TABLE', estimate_percent=>1);

建立一个表common_table,用于后面关联查询

create table common_table
as
select rownum id, a.* from all_objects a where object_type='TABLE';

alter table common_table add constraint
common_table_pk primary key(id);

exec dbms_stats.gather_table_stats(user, 'COMMON_TABLE', estimate_percent=>1);

到此,课程的准备工作完成!


实验二:oracle 的结构体系

一、oracle实例与数据库

实例包含进程和内存。oracle的进程可以通过v$process这张表进行查询。而内存占用参数可以查询memory_target(oracle 11g)或者sga_target和pga_target(oracle 10g)来查看。

select pid, pname, round(pga_used_mem/1024/1024,2)||'MB' 
from v$process;

数据库包括一系列操作系统的文件,其中最重要的是数据文件。可以通过查询v$datafile这张表进行查看。

select name, blocks from v$datafile;

二、pga, sga的查看与配置

pga的状态,通过查看v$pgastat这张表。在oracle 10g版本下,需要配置参数pga_target来设置;而在oracle 11g的版本下,只需要配置memory_target这个参数。

select name||' | '||round(value/1024/1024)||'MB' from v$pgastat;

sga的状态,通过查看v$sgastat这张表。同样在oracle 11g下面,通过配置memory_target这个参数来设置。

select * from v$sgastat;

三、内存参数设置。

内存参数主要通过pga_aggregate_target, sga_target, sga_max_size, memory_target 以及 memory_max_target等参数。这些参数都是写在spfile文件中的,所以参数的修改也是在spfile中。

SQL> show parameter sga_max_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_max_size                         big integer 512M

SQL> alter system set sga_target=600M;
alter system set sga_target=600M
*
第 1 行出现错误:
ORA-02097: 无法修改参数, 因为指定的值无效
ORA-00823: 指定的 sga_target 的值大于 sga_max_size

设置sga_target大于sga_max_size出现错误,要增大sga_target必须增大sga_max_size
sga_max_size为静态的参数,只能修改spfile的值

修改spfile文件中的sga_max_size后,系统运行的sga_max_size仍然为512M,需要重启数据库,参数才会修改。

alter system set sga_max_size=600M scope=spfile;

系统已更改。

SQL> show parameter sga_max_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_max_size                         big integer 512M

也可以通过查看pfile并修改达到更改参数的目的

create pfile='e:/newpfile.ora' from spfile;

文件已创建。

create spfile from pfile=‘d:/newpfile.ora’ 

四、oracle的事务处理方式和并发方式

思考以下问题:

查看和修改redo日志文件。

查看日志文件组,如果发现日志文件过小,可以进行调整。

select group#, sequence#, members, bytes, status, archived from v$log;

新增文件组4

alter database add logfile 
group 4 (‘e:/oracle/product/10.0.2/oradata/ORCL/redo41.log') size 200m;

切换重做日志

alter system switch logfile;

实验三:oracle的SQL调优

一、oracle语句的执行计划

设置终端输出执行时间:

set timing on

为了每次执行过程的公平,执行前都将缓存给清理干净。

alter system flush buffer_cache;

分别执行一下以下两个过程, 请分别记录一下执行时间:
过程1:

begin
  for i in 1..100000
  loop
      execute immediate 
    'select object_name from big_table where id=:x' using i;
  end loop;
end;
/

过程2:

begin
  for i in 1..100000
  loop
      execute immediate 
    'select object_name from big_table where id='||i ;
  end loop;
end;
/

思考一下问题:

我们来看一下一个典型的sql语句的执行过程。

set autotrace on

select a.object_name 
from 
big_table a inner join common_table b 
on ( a.object_id=b.object_id)
where a.id=100;

二、索引及连接方式

通过实验比较B树索引与位图索引的性能差别。

像前面准备的时候一样,通过all_objects这个视图来创建两个表btree_table, bitmap_table,分别用B树索引和位图索引来对这两个表中的OBJECT_TYPE, OWNER, NAMESPACE分别进行索引。

三、oracle语句优化

下面那些语句会使用到btree_table表的索引?

语句一:

select * from btree_table where owner||'.'||object_type='SYS.TABLE';

语句二:

select * from btree_table where owner like '%S';

语句三:

select * from btree_table where owner like 'S%';

语句四:

select * from btree_table where object_type like 'TABLE%';

语句五:

select * from btree_table where object_type like '%TABLE';

语句六:

select * from btree_table where namepace-10>0;

语句七:

select * from btree_table where namepace>10;

语句八:

select * from btree_table where namepace<>10;

语句九:

select * from btree_table where namepace>10 or namepace<10;

四、生成awr报告

SQL> @?/RDBMS/ADMIN/awrrpt.sql (注:?是ORACLE_HOME)
输入 report_type 的值:html     (注:确定报告的格式)
输入 num_days 的值:1     (注:选择快照的天数)
输入 begin_snap 的值:425     (注:起始快照)
输入 end_snap 的值:427     (注:结束快照)
输入 report_name 的值:d:\scmis-awr-2011-10-29.html     (注:报告生成的名称和位置)

五、生成addm报告

SQL> @?/RDBMS/ADMIN/addmrpt.sql (注:?是ORACLE_HOME)

实验四:oracle物理存储优化

一、行迁移的产生和清除

建一个表,用来做行迁移的实验。

create table chain_table(id number, name varchar(4000));

往表中插入2000行数据

declare
    i number;
    begin
        for i in 1..2000 
        loop
        insert into chain_table values (i, rpad('abc', 100));
        end loop;
    commit;
end;
/

更新表,使得字符串都变成2000个字符

update chain_table set name=rpad(‘123’, 2000, '*');
commit;

强制回写到数据库中。并且清除缓存。

alter system checkpoint;
alter system flush buffer_cache;

查询行链接,首次执行,运行脚本utlchain.sql生成相关分析用表。

@?/rdbms/admin/utlchain.sql

开始分析行链接情况。

analyze table chain_table list chained rows;
select * from CHAINED_ROWS;

方法一:清除行链接, 最简单的方法就是复制一下表,然后清除数据,再复制进去。对于没有外键限制的表,可以采取这种方式。

create table chain_table_tmp as select * from chain_table ;
truncate table chain_table
insert into chain_table select * from table_name_tmp

方法二:采取标准的处理方法,使用行移动的方法来解决。

alter table utlrp.sql enable row movement ; 
alter table chain_table shrink space compcat;
alter table chain_table shrink space; 

最后运行命令,重新编译无效对象。

@?/rdbms/admin/utlrp.sql 

二、多种数据库表的应用

  1. 表压缩的应用

使用前面准备的bigtable复制一个一样的表,使用的表压缩技术,然后进行存储的比较。

create table bigtable_1 compress as select * from bigtable;

收集表的信息:

sql>execute dbms_stats.gather_table_stats(ownname=>'SYS', tabname=>'BIGTABLE');
sql>execute dbms_stats.gather_table_stats(ownname=>'SYS', tabname=>'BIGTABLE_1');

统计一下空间对比:

select table_name||'|'||blocks||'|'||num_rows 
from dba_tables 
where table_name like ‘BIGTABLE%’;

空间差异是多少?

  1. 聚簇表

构建一个索引聚簇表,使用列owner varchar(30)作为聚簇列,复制视图sys.all_tables和sys.all_views分别建立在这个聚簇上。

create cluster mycluster( owner varchar(30)) size 128;

create table mytables
(  
    owner varchar(30), 
    table_name varchar(100)
)cluster mycluster(owner);

create table myview
(
    owner varchar(30), 
    view_name(100)
)cluster mycluster(owner);

insert into mytables(owner, table_name)
select owner, table_name from sys.all_tables;

insert into myview(owner, view_name)
select owner, view_name from sys.all_views;

为了对比,我们建立两个没有通过聚簇关联的表。并且建立索引,我们看看结果。

create table mytable_1 as select * from mytables;
create table myview_1 as select * from myview;
create index mytable_1_index on mytable_1(owner);
create index myview_1_index on myview_1(owner);

强制oracle写磁盘,并且清空缓存。

alter system checkpoint;
alter system flush buffer_cache;

对比看看关联结果,耗费的差异情况。

set autotrace traceonly
select * from myviews a , mytables b where a.owner=b.owner and a.owner=‘HR';
select * from myview_1 a , mytable_1 b where a.owner=b.owner and a.owner =‘HR’;
  1. IOT表

通过all_objects的OBJECT_ID, OBJECT_NAME建立一个IOT表。

create table iot_table
( 
    object_id number,
    object_name varchar(30),
    primary key(object_id)
) organization index;

insert into iot_table select object_id, object_name from all_objects;

另外,构造一个一样的普通表,对比一下看看。

create table short_table
( 
    object_id number,
    object_name varchar(30),
    primary key(object_id)
) as select * from iot_table;

写磁盘,请缓存,比较一下看看。

alter system checkpoint;
alter system flush buffer_cache;

set autotrace on
select * from iot_table where object_id=23;
select * from short_table where object_id=23;

三、表分区机制与应用

1. 区间分区例子

建立一个表,按时间进行区间分区。

create table range_example
(    rang_key_column date NOT NULL,
     data  varchar(20)
)
partition by range(rang_key_column)
(   
    partition part_1 values less than (to_date('2010-01-01', 'yyyy-mm-dd')) compress,
    partition part_2 values less than (to_date('2011-01-01', 'yyyy-mm-dd')) compress,
    partition part_max values less than (maxvalue)
) ;

将最后一个分区再切分成两个分区。

alter table range_example 
split partition part_max at (to_date('2012-01-01', 'yyyy-mm-dd')) 
into ( partition part_3, partition part_max);

2. 散列分区例子

建立一个表,以散列值进行分区

Create table hash_example
(    hash_key_column date NOT NULL,
     data  varchar(20)
)  Partition by hash(hash_key_column)
(   partition part_1,
    partition part_2 
); 

增加一个散列分区。

alter table hash_example add partion part_3;

3. 列表分区例子

根据列表内容分成多个区。

create table list_example
(   state_name varchar(32),
    data varchar(20)
) partition by list(state_name)
(  partition part_1 values('guangdong‘, ‘guangxi’),
   partition part_2 values('shanghai'),
   partition part_default values(default)
)
alter table list_example split partition part_default values('beijing') into
(  partition part_3, partition part_default);

4. 间隔分区例子

create table audit_trail 
( 
    ts  timestamp, 
    data  varchar2(30) 
)partition by range(ts)  
interval(numtoyminterval(1, 'month')) 
store in (users, example) 
(partition p0 values less than(to_date('01-01-1900')));

当插入一行数据的时候,系统自动增加一个区间。

insert into audit_trail(ts, data) 
values ( to_timestamp(’27-feb-2010’, ‘dd-mon-yyyy’), ‘xx’);

5. 引用分区例子

建立一个分区父表。

create table orders 
(
    order#  number primary key, 
    order_date date, 
    data varchar2(30) 
) enable row movement partition by range( order_date)
(  
    partition part_2009 values less than(to_date(’01-01-2010’, ‘dd-mm-yyyy’)) ,
     partition part_2010 values less than(to_date(’01-01-2011’, ‘dd-mm-yyyy’))  
);

insert into orders values(1, to_date(’01-jun-2009’, ‘dd-mon-yyyy’), ‘xxx’);
insert into orders values(1, to_date(’01-jun-2010’, ‘dd-mon-yyyy’), ‘xxx’);

建立一个子表的引用分区。

create table order_line_items
( 
    order# number, 
    line# number, 
    data varchar2(30), 
    constraint c1_pk primary key(order#, line#), 
    Constraint c1_fk_p foreign key(order#) references orders
) 
    enable row movement partition by reference(c1_fk_p) ;

向分区子表插入数据。

insert into order_line_items values(1, 1, ‘yyy’);
insert into order_line_items values(2, 1, ‘yyy’);

引用分区的便利之处在于:当你将父表中的分区删除掉,那么oracle也会自动级联传递到子表中,同时删除子表对应的分区。这样避免了由于外键约束而不能删除的问题。

alter table orders drop partition part_2009 update global indexes;

6.组合分区的例子

create table composite_example 
( 
    range_key_column  date,
      hash_key_column    int,
      data  varchar2(20)
) partition by range ( range_key_column)
    subpartition by hash( hash_key_column) subpartitions 2
    (  
        partition part_1  values less than (to_date('01/01/2008', 'dd/mm/yyyy'))
        ( 
            subpartition part_1_sub_1,  
            subpartition part_1_sub_2 
        ),
           partition part_2  values less than (to_date(’01/01/2008’, ‘dd/mm/yyyy’))
        ( 
            subpartition part_2_sub_1,  
            subpartition part_2_sub_2 
        )
    )
)

7.实验

内容:

四、索引分区

1. 局部索引分区

create table partitioned_table
( 
    a int, 
    b int, 
    data char(20)
) partition by range(a)  
(   partition part_1 values less than(2) tablespace p1,
    partition part_2 values less than(3) tablespace p2
);

局部前缀索引

create index local_prefixed on partitioned_table (a, b) local;

局部非前缀索引

create index local_nonprefixed on partitioned_table (b) local;

2. 全局索引分区

create table partitioned
(
    timestamp date, 
    id int
) partition by range(timestamp)  
(   
    partition part_1 values less than (to_date('01-01-2000', 'dd-mm-yyyy')),
    partition part_2 values less than (to_date('01-01-2001', 'dd-mm-yyyy')),
    partition part_3 values less than (to_date('01-01-2002', 'dd-mm-yyyy')),
    partition part_4 values less than (to_date('01-01-2003', 'dd-mm-yyyy')),
);

create index partitioned_index on partitioned(id) global partiton by range(id)
(   partition part_1 values less than (1000),
    partition part_2 values less than (maxvalue)
);

3. 滑动窗口和索引

建立一个分区及全局索引,用以做滑动窗口。

create table partitioned
( 
    timestamp date, 
    id int 
)partition by range (timestamp)
( 
    partition fy_2004 values less than (to_date('01-01-2005', 'dd-mm-yyyy')),
    partition fy_2005 values less than (to_date('01-01-2006', 'dd-mm-yyyy'))  
);

create index partitioned_idx_global on partitioned(timestamp) global; 

利用all_object 生成样例数据。

insert into partitioned partition(fy_2004) 
select to_date('31-12-2004','dd-mm-yyyy')-mod(rownum,360), object_id 
from all_objects;

insert into partitioned partition(fy_2005) 
select to_date('31-12-2005','dd-mm-yyyy')-mod(rownum,360), object_id
from all_objects;

建立空表fy_2004,用于存放旧的数据。

create table fy_2004 (timestamp date, id int);
create index fy_2004_idx on  fy_2004(timestamp date);

建立表fy_2006,里面存放新的数据。下面进行数据的交换.

create table fy_2006(timestamp date, id int)
select to_date('31-12-2006', 'dd-mm-yyyy') – mod(rownum, 360), object_id
from all_objects;

create index fy_2006_idx on  fy_2006(timestamp date);

归档数据并清除旧分区

alter table partitioned 
exchange partition fy_2004 
with table fy_2004 
including indexes without validation update global indexes;

alter table partitioned drop partiton fy_2004 update global indexes

前面新数据已经装载,这里新增空白分区并交换数据和索引。

alter table partitioned 
    add partition fy_2006 less than ( to_date('01-01-2007', 'dd-mm-yyyy'));

alter table partitioned 
    exchange partition fy_2006
    with table fy_2006 
    including indexes without validation
    update global indexes ;

4. 案例题一

表分区在数据仓库/决策系统中,分区是一个强大的工具,它一方面使你的数据存储更加方便有效,同时通过合理的查询使效率提升。在地市的实际工作中,我们常常使用表分区来解决一些存储量巨大的历史数据。
我们碰到了一个难题,我们有一个数据仓库,数据量非常大,月均数据量超过2G。总体数据量已超过2T,数据量过高造成运行慢,备份能力不足。我们应该如何设计这个系统呢?

问题:

5. 案例题二

某地市的触点营销平台,每月上架大量的触点数据。因为触点数据使用周期比较长,客户数量多,所以数据量较大。1月-4月数据量已经超过上亿条。开发人员按照上架时间对触点数据进行分区,并构造全局索引,发现数据批量导入的速度仍然非常慢。

问题:


实验五:oracle备份与恢复

一、flashback(误操作恢复)

flashback的特点:

flashback database 用于恢复数据库到某一个时点
flashback table 用于恢复误drop的表
flashback query 实现行级恢复
flashback table 恢复表到先前状态

检查是否启用了flash recovery area

show parameter db_recovery_file

检查是否启用了自动归档模式

archive log list;

启用自动归档模式

startup mount;
alter database archivelog;
alter database open

启用flashback_on

alter database flashback on

查看scn与时间对应关系。

select scn, to_char(time_dp, 'yyyymmdd-hh24:mi:ss') 
from sys.smon_scn_time;

恢复到时间点或者scn

flashback database to 
timestamp to_timestamp('09-10-14 14:37:05′,'yy-mm-dd hh24:mi:ss');

flashback database to scn 1385839

误删除了一个表T

drop table gmcc.t;

闪回表T

flashback table gmcc.t to before drop;

误删除了一个表中的数据

delete from gmcc.t where x>1;
commit;

通过flashback仍然可以查询之前的版本数据, 然后通过插入或者覆盖的方式来恢复表的行数据。

select * from gmcc.t 
as of timestamp to_timestamp('20150422 10:55:00', 'yyyymmdd hh24:mi:ss');

flash table

允许行移动

alter table gmcc.t enable row movement;

闪回表数据

flashback table gmcc.t 
to timestamp to_timestamp('20150422 10:55:00', 'yyyymmdd hh24:mi:ss');

为了避免恢复错误,可以查询一下操作日志,确认恢复到的时间。

select sql_text from v_$sql 
where sql_text like 'delete%gmcc.t%' 
order by last_active_time asc;

二、Imp/exp(数据迁移与恢复)

由于Impdp/expdp是在服务器端的导入导出,所以主要使用的区别是指明服务端路径。

create directory dpdata1 as '/home/oracle/dpdata1';
grant read, write on directory dpdata1 to gmcc;

导出的例子

$expdp gmcc/gmcc tables=mytable directory=dpdata1 dumpfile=mytable.dmp  \
job_name=MYTABLE_EXPORT

导入的例子

$impdp gmcc/gmcc tables=mytable directory=dpdata1 dumpfile=mytable.dmp  \
job_name=MYTABLE_EXPORT

三、Rman(标准的备份与恢复)

简单实用

连接数据库,进入rman

$ rman target / 

查看参数

RMAN> show all; 

查看备份情况

RMAN> list backup; 

查看数据库的表空间和数据文件

RMAN> report schema; 

简单的全备份,数据库datafile和spfile都会保存

RMAN>  backup database format ‘e:/whole_%d_%U’ 

启用autobackup,并备份controlfile

RMAN> configure controlfile autobackup on; 
RMAN> backup current controlfile

进入nomount的状态后,恢复controlfile

RMAN>startup nomount; 
RMAN>restore controlfile from autobackup; 

进入mount的状态后,恢复数据库

RMAN>startup mount; 
RMAN>restore database; 

备份策略

bak_inc0:周日进行数据库的全备份。

run {
        allocate channel ch1 type disk;
        backup as compressed backupset  incremental level 0
        format '/u01/oracle/bk/rmbk/incr0_%d_%U'
        tag 'day_incr0'
        database plus archivelog delete input;
        release channel ch1;
        }

bak_inc2:周一二,四五六,进行数据库的增量备份。

run {
        allocate channel ch1 type disk;
        backup as compressed backupset  incremental level 2
        format '/u01/oracle/bk/rmbk/incr2_%d_%U'
        tag 'day_incr0'
        database plus archivelog delete input;
        release channel ch1;
        }

bak_inc1:周三进行数据库的增量备份。

run {
        allocate channel ch1 type disk;
        backup as compressed backupset  incremental level 1
        format '/u01/oracle/bk/rmbk/incr1_%d_%U'
        tag 'day_incr0'
        database plus archivelog delete input;
        release channel ch1;
        }

脚本通过语句执行

rman target / log=/u01/oracle/bk/log/bak_inc0.log \
append cmdfile = /u01/oracle/bk/scripts/bak_inc0.rcv

在linux系统,通常是设置crontab来设置定期执行,而在windows系统中设置计划任务来执行。

上一篇下一篇

猜你喜欢

热点阅读