Oracle 在线重定义(中)

6ee12dbba607e6e2ecb3d63841355db0.gif

作者 | JiekeXu

来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT)

如需转载请联系授权 | (个人微信 ID:JiekeXu_DBA)

大家好,我是 JiekeXu,很高兴又和大家见面了,今天和大家一起来看看  Oracle 在线重定义(中),欢迎点击上方蓝字“JiekeXu DBA之路”关注我的公众号,标星或置顶,更多干货第一时间到达!

目  录
    在线重定义测试实践
        查看用户权限并赋权
        创建测试表
        创建 16k 大小表空间
        插入表数据
            检查碎片率
            表碎片整理
        检查是否可以进行在线重定义
        创建一个临时分区表 test.interim
        开始重新定义过程
        终止在线重定义
        复制依赖对象
        可选择同步临时表
        完成重新定义
        查看完成后的新表
        分区表相关视图
    测试环境普通表改分区表示例

在线重定义测试实践

前面一篇已经介绍过了《Oracle 在线重定义(中)》相关基础知识及示例,这里则是接着第一篇继续进行在线重定义的介绍。

————————————————————————————
微信公众号:JiekeXu DBA之路
墨天轮:https://www.modb.pro/u/4347
CSDN :https://blog.csdn.net/JiekeXu
腾讯云:https://cloud.tencent.com/developer/user/5645107
————————————————————————————

查看用户权限并赋权

查看用户所具有的角色

select *  from dba_role_privs where grantee='TEST';

查询角色包含哪些权限:

select *  from role_sys_privs where  role='&role';

查询用户系统权限:

select  *  from dba_sys_privs where  grantee='&username';
GRAN PRIVILEGE                                ADM COM INH
---- ---------------------------------------- --- --- ---
TEST ALTER SYSTEM                             NO  NO  NO
TEST SELECT ANY TABLE                         NO  NO  NO
TEST UNLIMITED TABLESPACE                     NO  NO  NO
TEST CREATE SESSION                           NO  NO  NO

查询用户具有的表权限:

col PRIVILEGE for a15
col GRANTEE for a15 
col OWNER for a15
select  *  from dba_tab_privs where  grantee='TEST';
GRANTEE         OWNER           TABLE_NAME                     GRANTOR              PRIVILEGE       GRA HIE COM TYPE                     INH
--------------- --------------- ------------------------------ -------------------- --------------- --- --- --- ------------------------ ---
TEST            SYS             DBA_HIST_SQLTEXT               SYS                  SELECT          NO  NO  NO  VIEW                     NO
用户在线重定义需要的权限:
GRANT EXECUTE_CATALOG_ROLE TO TEST;
GRANT CREATE TABLE,CREATE MATERIALIZED VIEW TO TEST;
GRANT CREATE ANY TABLE,ALTER ANY TABLE,DROP ANY TABLE,LOCK ANY TABLE,SELECT ANY TABLE TO TEST;
GRANT CREATE ANY TRIGGER,CREATE ANY INDEX TO TEST;

创建测试表

CREATE TABLE test.original( 
   col1 NUMBER PRIMARY KEY,
   col2 VARCHAR2(10),
   col3 CLOB,
   col4 DATE)
ORGANIZATION INDEX;

d73e2c7b29dc4ca7a71231bc3cbce3a5.png

创建 16k 大小表空间

alter system set db_16k_cache_size = 16m;
select file_id,file_name,bytes/1024/1024,AUTOEXTENSIBLE from dba_data_files  where tablespace_name='USERS';
CREATE TABLESPACE testredeftbs DATAFILE '/u01/app/oracle/oradata/TESTOGG/testredef01.dbf' SIZE 500M   EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT AUTO BLOCKSIZE 16384;

插入表数据

DECLARE
  V_CLOB CLOB;
BEGIN
   FOR I IN 0..999 LOOP
      V_CLOB := NULL;
      FOR J IN 1..1000 LOOP
         V_CLOB := V_CLOB||TO_CHAR(I,'0000');
      END LOOP;
      INSERT INTO test.original VALUES(I,TO_CHAR(I),V_CLOB,SYSDATE+I);
      COMMIT;
   END LOOP;
   COMMIT;
END;
/
DELETE FROM test.original WHERE (COL1/3) <> TRUNC(COL1/3);


Commit;
select * from test.original WHERE COL1<=2;

b70bc096c1c1cfa2f15f21d0de91f927.png

检查碎片率
下表 SPACE_USAGE 过程参数  
https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/DBMS_SPACE.html#GUID-1115B610-8956-426F-B615-9118225F911F

c7a59ced86ace8494ba947c87494c3cc.png

set serverout on size 1000000
declare
p_fs1_bytes number;
p_fs2_bytes number;
p_fs3_bytes number;
p_fs4_bytes number;
p_fs1_blocks number;
p_fs2_blocks number;
p_fs3_blocks number;
p_fs4_blocks number;
p_full_bytes number;
p_full_blocks number;
p_unformatted_bytes number;
p_unformatted_blocks number;
begin
dbms_space.space_usage(
segment_owner => 'TEST',
segment_name => 'ORIGINAL',
segment_type => 'TABLE',
fs1_bytes => p_fs1_bytes,
fs1_blocks => p_fs1_blocks,
fs2_bytes => p_fs2_bytes,
fs2_blocks => p_fs2_blocks,
fs3_bytes => p_fs3_bytes,
fs3_blocks => p_fs3_blocks,
fs4_bytes => p_fs4_bytes,
fs4_blocks => p_fs4_blocks,
full_bytes => p_full_bytes,
full_blocks => p_full_blocks,
unformatted_blocks => p_unformatted_blocks,
unformatted_bytes => p_unformatted_bytes
);
dbms_output.put_line('FS1: blocks = '||p_fs1_blocks);
dbms_output.put_line('FS2: blocks = '||p_fs2_blocks);
dbms_output.put_line('FS3: blocks = '||p_fs3_blocks);
dbms_output.put_line('FS4: blocks = '||p_fs4_blocks);
dbms_output.put_line('Full blocks = '||p_full_blocks);
end;
/
FS1: blocks = 0
FS2: blocks = 2
FS3: blocks = 0
FS4: blocks = 0
Full blocks = 11

FS1表明有 0 个数据块具有 0%-25% 的空闲空间,FS2 表明有 2 个数据块具有 25%-50% 的空闲空,间FS3 表明有 0 个数据块具有 50%-75% 的空闲空间,FS4 表明有 0 个数据块具有 75%-100% 繁荣空闲空间,FULL 表明有 11个 满的数据块。

--分区表碎片查看
col TABLE_OWNER for a30
col TABLE_NAME for a30
col PARTITION_NAME for a30
col TABLESPACE_NAME for a30
select TABLE_OWNER,TABLE_NAME,PARTITION_NAME,TABLESPACE_NAME,NUM_ROWS,LAST_ANALYZED from DBA_TAB_PARTITIONS where TABLE_OWNER='TEST';


set serveroutput on
declare
v_unformatted_blocks number;
v_unformatted_bytes number;
v_fs1_blocks number;
v_fs1_bytes number;
v_fs2_blocks number;
v_fs2_bytes number;
v_fs3_blocks number;
v_fs3_bytes number;
v_fs4_blocks number;
v_fs4_bytes number;
v_full_blocks number;
v_full_bytes number;
begin
dbms_space.space_usage ('TEST', 'ORIGINAL', 'TABLE PARTITION', v_unformatted_blocks,
v_unformatted_bytes, v_fs1_blocks, v_fs1_bytes, v_fs2_blocks, v_fs2_bytes,
v_fs3_blocks, v_fs3_bytes, v_fs4_blocks, v_fs4_bytes, v_full_blocks, v_full_bytes, 'PAR1');
dbms_output.put_line('Unformatted Blocks = '||v_unformatted_blocks);
dbms_output.put_line('FS1 Blocks = '||v_fs1_blocks);
dbms_output.put_line('FS2 Blocks = '||v_fs2_blocks);
dbms_output.put_line('FS3 Blocks = '||v_fs3_blocks);
dbms_output.put_line('FS4 Blocks = '||v_fs4_blocks);
dbms_output.put_line('Full Blocks = '||v_full_blocks);
end;
/

8a7d08da2abeda9d2329a110e262d49c.png

表碎片整理

通过碎片整理来收缩空间,调整高水位线,方法比较简单,首先需要启用行移动,然后 alter table …… shrink space 即可完成,期间不会阻塞 DML 操作,可能时间会很久,建议业务低峰期间操作。

alter table prod.T_ZDW_DOWN_SYNC_REC enable row movement;
alter table prod.T_ZDW_DOWN_SYNC_REC shrink space cascade;
alter table prod.T_ZDW_DOWN_SYNC_REC disable row movement;

除了使用 shrink space 外,还有截断表,move 表,导入导出。但是 truncate 表直接清理数据,一般情况下不可取;alter table t move; move 表会使索引失效,移动完需要 rebuild 重新建索引,移动表时对数据行的 rowid 有所变更,而索引中又包含了 rowid, 故 move 表会使索引失效。最后导出导入数据时,不能有新数据进入,这点也不太友好,故此推荐 shrink space 。

set lines 200 pages 1000
col frag format 999999.99
col owner format a30;
col table_name format a30;
col frag for a20
select a.owner,
       a.table_name,
       a.num_rows,
       a.avg_row_len,
       round(a.avg_row_len * a.num_rows / 1024 / 1024, 2) real_bytes_MB,
       round(b.seg_bytes_mb, 2) seg_bytes_mb,
       decode(a.num_rows,0,100,(1 - round(a.avg_row_len * a.num_rows / 1024 / 1024 / b.seg_bytes_mb,2)) * 100) || '%' frag_percent
  from dba_tables a,
       (select owner, segment_name, sum(bytes / 1024 / 1024) seg_bytes_mb
          from dba_segments
         group by owner, segment_name) b
 where a.table_name = b.segment_name
   and a.owner = b.owner
   --and a.owner not in ('SYS','SYSTEM','OUTLN','DMSYS','TSMSYS','DBSNMP','WMSYS','EXFSYS','CTXSYS','XDB','OLAPSYS','ORDSYS','MDSYS','SYSMAN')
   and a.owner in ('OGG','PROD')
   and a.table_name='T_ZDW_DOWN_SYNC_REC'
   and decode(a.num_rows,0,100,(1 - round(a.avg_row_len * a.num_rows / 1024 / 1024 / b.seg_bytes_mb,2)) * 100) > 50
 order by b.seg_bytes_mb desc;

31d0751b0e50ef37a8146b51b403bcc9.png

检查是否可以进行在线重定义

BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE(
    uname        => 'test',
    tname        => 'original',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK);
END;
/

创建一个临时分区表 test.interim

CREATE TABLE test.interim( 
    col1 NUMBER,
    col3 TIMESTAMP,
    col4 CLOB,
    col5 VARCHAR2(3))
    LOB(col4) STORE AS SECUREFILE (NOCACHE FILESYSTEM_LIKE_LOGGING)
    PARTITION BY RANGE (COL1) (
       PARTITION par1 VALUES LESS THAN (333),
       PARTITION par2 VALUES LESS THAN (666),
       PARTITION par3 VALUES LESS THAN (MAXVALUE))
   TABLESPACE testredeftbs
   ROW STORE COMPRESS ADVANCED;

开始重新定义过程

BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
     uname        => 'test',
     orig_table   => 'original',
     int_table    => 'interim',
     col_mapping  => 'col1 col1, TO_TIMESTAMP(col4) col3, col3 col4',
     options_flag => DBMS_REDEFINITION.CONS_USE_PK);
END;
/

终止在线重定义

BEGIN
  DBMS_REDEFINITION.abort_redef_table (
       uname        => 'test',
         orig_table   => 'original',
         int_table    => 'interim');
END;
/

529a8ca5eff33f213759be47241e3c17.png

由于 SQLPLUS 对时间格式化的不兼容性而出错,故需 abort 终止,然后使用 PLSQL 开始。

a12a0023ac01b3725983492ed4791299.png

复制依赖对象

DECLARE
num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname            => 'test', 
    orig_table       => 'original',
    int_table        => 'interim',
    copy_indexes     => DBMS_REDEFINITION.CONS_ORIG_PARAMS, 
    copy_triggers    => TRUE, 
    copy_constraints => TRUE, 
    copy_privileges  => TRUE, 
    ignore_errors    => TRUE, 
    num_errors       => num_errors);
END;
/

可选择同步临时表

BEGIN 
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname       => 'test', 
    orig_table  => 'original',
    int_table   => 'interim');
END;
/

完成重新定义

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname       => 'test', 
    orig_table  => 'original',
    int_table   => 'interim');
END;
/

c013af4e171e09200e2a544fcb2cd481.png

查看完成后的新表

select count(*) from original partition(par3);

f5d4369243e2f28af38409f80ef5ff99.png

分区表相关视图

  1. 显示当前用户可访问的所有分区表信息﹕
         ALL_PART_TABLES

  2. 显示当前用户所有分区表的信息﹕
         USER_PART_TABLES

  3. 显示表分区信息 显示数据库所有分区表的详细分区信息﹕
         DBA_TAB_PARTITIONS

col TABLE_OWNER for a12
col TABLE_NAME for a28
col PARTITION_NAME for a15 
select TABLE_OWNER,TABLE_NAME,PARTITION_NAME,num_rows,last_analyzed from DBA_TAB_PARTITIONS where TABLE_OWNER='T2_OS';


select partition_name from DBA_TAB_PARTITIONS where table_owner='SYS' and TABLE_NAME='USER_LOG';

4.显示当前用户可访问的所有分区表的详细分区信息﹕
     ALL_TAB_PARTITIONS

5.显示当前用户所有分区表的详细分区信息﹕
     USER_TAB_PARTITIONS

6.显示子分区信息 显示数据库所有组合分区表的子分区信息﹕
     DBA_TAB_SUBPARTITIONS

7.显示当前用户可访问的所有组合分区表的子分区信息﹕
     ALL_TAB_SUBPARTITIONS

8.显示当前用户所有组合分区表的子分区信息﹕
     USER_TAB_SUBPARTITIONS

9.显示分区列 显示数据库所有分区表的分区列信息﹕
     DBA_PART_KEY_COLUMNS
10.显示当前用户可访问的所有分区表的分区列信息﹕
     ALL_PART_KEY_COLUMNS
11.显示当前用户所有分区表的分区列信息﹕
     USER_PART_KEY_COLUMNS
12.显示子分区列 显示数据库所有分区表的子分区列信息﹕
     DBA_SUBPART_KEY_COLUMNS
13.显示当前用户可访问的所有分区表的子分区列信息﹕
     ALL_SUBPART_KEY_COLUMNS
14.显示当前用户所有分区表的子分区列信息﹕
     USER_SUBPART_KEY_COLUMNS
15.自动创建分区示例

CREATE TABLE sys_yw.user_log
(
   user_id           VARCHAR2 (30),
   session_id        NUMBER (8),
   HOST              VARCHAR2 (30),
   last_program      VARCHAR2 (48),
   last_action       VARCHAR2 (32),
   last_module       VARCHAR2 (32),
   logon_day         DATE,
   logon_time        VARCHAR2 (10),
   logoff_day        DATE,
   logoff_time       VARCHAR2 (10),
   elapsed_minutes   NUMBER (8)
) 
PARTITION BY RANGE(logon_day)  interval (numtoyMinterval (1,'YEAR'))
       (PARTITION P_YEAR2023 VALUES LESS THAN (to_date('2023-12-31','yyyy-mm-dd')));

PARTITION BY RANGE (CREATE_TIME) INTERVAL (NUMTODSINTERVAL(1, ‘day’)) --设定通过字段’CREATE_TIME’来分区,自动创建间隔 1 天.

(partition part_t01 values less than(to_date(‘2023-08-19’, ‘yyyy-mm-dd’))); --初始建立一个分区,注意使用 less than的时候,日期设定为当天日期+1,代表今天的数据存储在当前分区。

测试环境普通表改分区表示例

BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE(
    uname        => 'OUS',
    tname        => 'T_INVOICE_ATTRIBUTION',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK);
END;
/

创建临时分区表

使用 PLSQL 查看创建表的 SQL 语句或者使用如下 GET_DDL 获取建表语句

set long 9999 line 456 pages 0
SELECT DBMS_METADATA.GET_DDL('TABLE','T_INVOICE_ATTRIBUTION','OUS') DDL_SQL FROM DUAL;
查看 create_time 列最小时间,以此作为初始分区
select min(create_time) from OUS.T_INVOICE_ATTRIBUTION_ABLE;

创建表

create table OUS.T_INVOICE_ATTRIBUTION_BAK
(
  sequence_no         NUMBER(18) not null,
  pk_id               VARCHAR2(36) not null,
  platform_code       VARCHAR2(500) not null,
  business_invoice_id VARCHAR2(36) not null,
  fk_invoice_id       VARCHAR2(36) not null,
  product_code        VARCHAR2(36) not null,
  supplier_code       VARCHAR2(36) not null,
  supplier_name       VARCHAR2(200) not null,
  counterparty_code   VARCHAR2(36) not null,
  invoice_buy         VARCHAR2(500),
  invoice_sell        VARCHAR2(500),
  counterparty_name   VARCHAR2(200) not null,
  finance_code        VARCHAR2(36) not null,
  finance_name        VARCHAR2(200) not null,
  head_finance_code   VARCHAR2(36),
  head_finance_name   VARCHAR2(200),
  invoice_type        VARCHAR2(36) not null,
  invoice_code        VARCHAR2(36) not null,
  invoice_number      VARCHAR2(36) not null,
  invoice_date        DATE,
  invoice_check_code  VARCHAR2(36),
  invoice_file_id     VARCHAR2(36),
  invoice_file_name   VARCHAR2(500),
  financing_state     VARCHAR2(36) not null,
  data_source         VARCHAR2(36),
  fk_user_updat       VARCHAR2(36),
  user_name_update    VARCHAR2(60),
  update_time         DATE,
  create_time         DATE not null,
  fk_user_create      VARCHAR2(36),
  user_name_create    VARCHAR2(60),
  is_delete           CHAR(1) default '0' not null,
  delete_time         DATE,
  fk_user_delete      VARCHAR2(36),
  user_name_delete    VARCHAR2(60),
  batch_number        VARCHAR2(36) default '_'
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (NUMTODSINTERVAL(1, 'day'))
(PARTITION SYS_01 VALUES LESS THAN (to_date('2023-07-01','yyyy-mm-dd')));
开始在线重定义
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
     uname        => 'OUS',
     orig_table   => 'T_INVOICE_ATTRIBUTION',
     int_table    => 'T_INVOICE_ATTRIBUTION_BAK',
     options_flag => DBMS_REDEFINITION.CONS_USE_PK);
END;
/

复制依赖对象

DECLARE
num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname            => 'OUS', 
    orig_table       => 'T_INVOICE_ATTRIBUTION',
    int_table        => 'T_INVOICE_ATTRIBUTION_BAK',
    copy_indexes     => DBMS_REDEFINITION.CONS_ORIG_PARAMS, 
    copy_triggers    => TRUE, 
    copy_constraints => TRUE, 
    copy_privileges  => TRUE, 
    ignore_errors    => TRUE, 
    num_errors       => num_errors);
END;
/

可选择同步临时表

BEGIN 
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname       => 'OUS', 
    orig_table  => 'T_INVOICE_ATTRIBUTION',
    int_table   => 'T_INVOICE_ATTRIBUTION_BAK');
END;
/

完成重新定义

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname       => 'OUS', 
    orig_table  => 'T_INVOICE_ATTRIBUTION',
    int_table   => 'T_INVOICE_ATTRIBUTION_BAK');
END;
/

收集统计信息

exec dbms_stats.gather_schema_stats('OUS');
exec dbms_stats.gather_table_stats('OUS','T_INVOICE_ATTRIBUTION');


BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'OUS',
                                tabname          => 'T_STATS',
                                estimate_percent => 100,
                                method_opt       => 'for all columns size auto',
                                no_invalidate    => FALSE,
                                degree           => 8,
                                cascade          => TRUE);
END;
/

全文完,希望可以帮到正在阅读的你,如果觉得此文对你有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~

欢迎关注我公众号【JiekeXu DBA之路】,第一时间一起学习新知识!以下四个地址可以
找到我,其他地址均属于盗版侵权爬取我的文章,而且代码格式、图片等均有错乱,不方
便阅读,欢迎来我公众号或者墨天轮地址关注我,第一时间收获最新消息。

欢迎关注我的公众号【JiekeXu DBA之路】,第一时间一起学习新知识!————————————————————————————
公众号:JiekeXu DBA之路
CSDN :https://blog.csdn.net/JiekeXu
墨天轮:https://www.modb.pro/u/4347
腾讯云:https://cloud.tencent.com/developer/user/5645107
————————————————————————————

9f482c894a77a7483d4df07fa9649080.gif

分享几个数据库备份脚本

一文搞懂 Oracle 统计信息
 
 

我的 Oracle ACE 心路历程

Oracle 主流版本不同架构下的静默安装指南
 
 

关机重启导致 ASM 磁盘丢失数据库无法启动

Oracle SQL 性能分析(SPA)原理与实战演练
 
 

Oracle 11g 升级到 19c 需要关注的几个问题

Windows 10 环境下 MySQL 8.0.33 安装指南

SQL 大全(四)|数据库迁移升级时常用 SQL 语句

OGG|使用 OGG19c 迁移 Oracle11g 到 19C(第二版)

Oracle 大数据量导出工具——sqluldr2 的安装与使用

从国产数据库调研报告中你都能了解哪些信息及我的总结建议

使用数据泵利用 rowid 分片导出导入 lob 大表及最佳实践

在归档模式下直接 rm dbf 数据文件并重启数据库还有救吗?
  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值