1. stop the database
2. start in restricted mode with "startup restrict"
3. enable table locks:
alter table scott.emp enable table lock;4. startup the database in normal mode, and you will now be able to aquire locks on the table.
Minimalistic Oracle contains a collection of practical examples from my encounters with Oracle technologies. When relevant, I also write about other technologies, like Linux or PostgreSQL. Many of the posts starts with "how to" since they derive directly from my own personal experience. My goal is to provide simple examples, so that they can be easily adapted to other situations.
alter table scott.emp enable table lock;4. startup the database in normal mode, and you will now be able to aquire locks on the table.
ORA-02449: unique/primary keys in table referenced by foreign keys
SELECT TABLE_NAME,CONSTRAINT_NAME,CONSTRAINT_TYPE,R_CONSTRAINT_NAME,STATUS FROM DBA_CONSTRAINTS WHERE OWNER = 'SH' AND CONSTRAINT_TYPE='R' AND R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM DBA_CONSTRAINTS WHERE TABLE_NAME='SALES_INTERIM')
TABLE_NAME | CONSTRAINT_NAME | CONSTRAINT_TYPE | R_CONSTRAINT_NAME | STATUS |
---|---|---|---|---|
INVOICES | TMP$$_INVOICES_FK0 | R | TMP$$_SALES_PK0 | DISABLED |
REFUNDS | TMP$$_REFUNDS_FK0 | R | TMP$$_SALES_PK0 | DISABLED |
REPLENISHMENT | TMP$$_REPLENISHMENT_FK0 | R | TMP$$_SALES_PK0 | DISABLED |
SELECT TABLE_NAME,CONSTRAINT_NAME,R_CONSTRAINT_NAME,STATUS FROM DBA_CONSTRAINTS WHERE TABLE_NAME in ( SELECT TABLE_NAME FROM DBA_CONSTRAINTS WHERE OWNER = 'Sh' AND CONSTRAINT_TYPE='R' AND R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM DBA_CONSTRAINTS WHERE TABLE_NAME='SALES_INTERIM') ) AND CONSTRAINT_TYPE='R' AND CONSTRAINT_NAME LIKE '%REPLENISHMENT%' OR CONSTRAINT_NAME LIKE '%INVOICES%' OR CONSTRAINT_NAME LIKE '%REFUNDS%' ORDER BY TABLE_NAME,CONSTRAINT_NAME;
TABLE_NAME | CONSTRAINT_NAME | R_CONSTRAINT_NAME | STATUS |
---|---|---|---|
INVOICES | INVOICES_FK | SALES_PK | ENABLED |
INVOICES | TMP$$_INVOICES_FK0 | TMP$$_SALES_PK0 | DISABLED |
REFUNDS | REFUNDS_FK | SALES_PK | ENABLED |
REFUNDS | TMP$$_REFUNDS_FK0 | TMP$$_SALES_PK0 | DISABLED |
REPLENISHMENT | REPLENISHMENT_FK | SALES_PK | ENABLED |
REPLENISHMENT | TMP$$_REPLENISHMENT_FK0 | TMP$$_SALES_PK0 | DISABLED |
alter session set nls_language='american'; set lines 200 set pages 0 set heading off set feedback off set trimspool on set verify off set echo off spool 7.alter_table.sql select 'spool 7.alter_table.log' from dual; SELECT 'alter table ' || B.OWNER || '.' || B.TABLE_NAME || ' drop constraint ' || B.CONSTRAINT_NAME || ';' FROM DBA_CONSTRAINTS A FULL OUTER JOIN DBA_CONSTRAINTS B ON A.CONSTRAINT_NAME = B.R_CONSTRAINT_NAME WHERE A.OWNER = 'SH' AND A.TABLE_NAME='SALES_INTERIM' AND B.R_CONSTRAINT_NAME IS NOT NULL; select 'exit' from dual; exit
alter table SH.INVOICES drop constraint TMP$$_INVOICES_FK0; alter table SH.REFUNDS drop constraint TMP$$_REFUNDS_FK0; alter table SH.REPLENISHMENT drop constraint TMP$$_REPLENISHMENT_FK0;
ERROR at line 1: ORA-14024: number of partitions of LOCAL index must equal that of the underlying table
select 'original table: ' || MAX(PARTITION_POSITION) "number of partitions" from dba_tab_partitions where table_name='SALES' union select 'interim table: ' || MAX(PARTITION_POSITION) from dba_tab_partitions where table_name='SALES_INTERIM' ;
number of partitions |
---|
interim table: 19 |
original table: 18 |
copy_indexes=>dbms_redefinition.cons_orig_params
copy_indexes=>0
set lines 200 spool analyze_part.sql set trimspool on set verify off set heading off set pages 0 set echo off set feedback off select 'alter session set nls_language=''american'';' from dual; select 'set timing on' from dual; select 'set lines 200' from dual; select 'set trimspool on' from dual; select 'spool analyze_part.log' from dual; select 'exec DBMS_STATS.GATHER_TABLE_STATS (OwnName=> ''TRACKER'', TabName => ''EVENTS'',partname =>''' || partition_name || ''' granularity => ''PARTITION'';' from dba_tab_partitions where table_name='EVENTS' and num_rows = 0 and partition_name like 'SYS%';Run the analyze-script:
sqlplus / as sysdba @analyze_part.sqlAfterwards, the num_rows column for the same partitions should show 0 (zero) rows. In other words, they can be safely dropped.
set lines 200 spool drop_empty_part.sql set trimspool on set verify off set heading off set pages 0 set echo off set feedback off select 'alter session set nls_language=''american'';' from dual; select 'set timing on' from dual; select 'set lines 200' from dual; select 'set trimspool on' from dual; select 'spool drop_empty_part.log' from dual; select 'ALTER TABLE ' || table_owner || '.' || table_name || ' DROP PARTITION ' || PARTITION_NAME || ' UPDATE INDEXES;' from dba_tab_partitions where table_name='EVENTS' and num_rows = 0 and partition_name like 'SYS%'; select 'exit' from dual; exitExecut the script:
sqlplus / as sysdba @drop_empty_part.sqlThe number of partitions in the original table and the interim table should now match. Now, execute the DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS again. You shouldn't see the ORA-14024 this time around :-)
SELECT UNIQUE TABLESPACE_NAME FROM DBA_SEGMENTS WHERE OWNER = 'FXMART';
TABLESPACE_NAME |
---|
FXDATA_2016 |
FX_MART_DATA |
FXDATA_2014 |
FXDATA_2015 |
exec dbms_tts.transport_set_check('FXDATA_2016,FX_MART_DATA,FXDATA_2014,FXDATA_2015', true);
SELECT * FROM TRANSPORT_SET_VIOLATIONS;
alter tablespace FXDATA_2016 read only; alter tablespace FX_MART_DATA read only; alter tablespace FXDATA_2014 read only; alter tablespace FXDATA_2015 read only;
CREATE OR REPLACE DIRECTORY DP AS '/u02/exports';5. In your source database, export the metadata for the tablespaces to be moved using data pump export.
userid='/ as sysdba' DIRECTORY=DP DUMPFILE=FXMOVE_TSS.dmp LOGFILE=FXMOVE_TSS.log JOB_NAME=FXMOVE TRANSPORT_TABLESPACES=FXDATA_2016,FX_MART_DATA,FXDATA_2014,FXDATA_2015 EXCLUDE=STATISTICS METRICS=YES
expdp parfile=expdp_tts.par
SELECT FILE_NAME FROM DBA_DATA_FILES WHERE TABLESPACE_NAME IN ( SELECT UNIQUE TABLESPACE_NAME FROM DBA_SEGMENTS WHERE OWNER = 'FXMART' );
FILE_NAME |
---|
/u02/oradata/proddb01/fx_mart_data.dbf |
/u02/oradata/proddb01/fxdata_2014.dbf |
/u02/oradata/proddb01/fxdata_2015.dbf |
/u02/oradata/proddb01/fxdata_2016.dbf |
scp -i /home/oracle/.ssh/destinationserver_rsa /u02/exports/FXMOVE_TSS.dmp oracle@destinationserver:/u02/exports/. scp -i /home/oracle/.ssh/destinationserver_rsa /u02/exports/fxdata_2016.dbf oracle@destinationserver:/u02/exports/. scp -i /home/oracle/.ssh/destinationserver_rsa /u02/exports/fxdata_2015.dbf oracle@destinationserver:/u02/exports/ scp -i /home/oracle/.ssh/destinationserver_rsa /u02/exports/fxdata_2014.dbf oracle@destinationserver:/u02/exports/ scp -i /home/oracle/.ssh/destinationserver_rsa /u02/exports/fx_mart_data.dbf oracle@destinationserver:/u02/exports/
alter tablespace FXDATA_2016 read write; alter tablespace FX_MART_DATA read write; alter tablespace FXDATA_2014 read write; alter tablespace FXDATA_2015 read write;
CREATE OR REPLACE DIRECTORY DP AS '/u02/exports';
drop tablespace FXDATA_2016 including contents and datafiles; drop tablespace FXDATA_2014 including contents and datafiles; drop tablespace FX_MART_DATA including contents and datafiles; drop tablespace FXDATA_2015 including contents and datafiles;
drop user FXMARTTST cascade; CREATE USER FXMARTTST IDENTIFIED BY mysecretpassword DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP PROFILE APP_SCHEMAS; -- Grant of system privileges and/or roles here
userid='/ as sysdba' DIRECTORY=DP DUMPFILE=FXMOVE_TSS.dmp LOGFILE=imp_FXMOVE_TSS.log JOB_NAME=FXMOVE TRANSPORT_DATAFILES=/u02/oradata/testdb01/fx_mart_data.dbf,/u02/oradata/testdb01/fxdata_2014.dbf,/u02/oradata/testdb01/fxdata_2015.dbf,/u02/oradata/testdb01/fxdata_2016.dbf REMAP_SCHEMA=FXMART:FXMARTTST METRICS=YES
alter tablespace FXDATA_2016 read write; alter tablespace FX_MART_DATA read write; alter tablespace FXDATA_2014 read write; alter tablespace FXDATA_2015 read write;
define owner = 'SCOTT'; define table_name = 'EMP'; BEGIN dbms_stats.set_table_prefs('&&owner','&&table_name','INCREMENTAL','TRUE'); dbms_stats.set_table_prefs('&&owner','&&table_name','INCREMENTAL_STALENESS','USE_STALE_PERCENT, USE_LOCKED_STATS'); dbms_stats.set_table_prefs('&&owner','&&table_name','DEGREE','DBMS_STATS.DEFAULT_DEGREE'); END; /
define owner = 'SCOTT'; define table_name = 'EMP'; set lines 200 set verify off col "incremental" format a20 col "incr staleness" format a40 col "incremental level" format a10 col "stale percent" format a20 col "synopsis type" format a40 col "degree" format a30 col "granularity" format a20 select dbms_stats.get_prefs('INCREMENTAL','&&owner','&&table_name') "incremental", dbms_stats.get_prefs('INCREMENTAL_STALENESS','&&owner','&&table_name') "incr staleness", dbms_stats.get_prefs('INCREMENTAL_LEVEL','&&owner','&&table_name') "incremental level", dbms_stats.get_prefs('STALE_PERCENT','&&owner','&&table_name') "stale percent", dbms_stats.get_prefs('APPROXIMATE_NDV_ALGORITHM','&&owner','&&table_name') "synopsis type", dbms_stats.get_prefs('DEGREE','&&owner','&&table_name') "degree" , dbms_stats.get_prefs('GRANULARITY','&&owner','&&table_name') "granularity" FROM DUAL /
incremental | incr staleness | incremental level | stale percent | synopsis type | degree | granularity |
---|---|---|---|---|---|---|
TRUE | USE_STALE_PERCENT, USE_LOCKED_STATS | PARTITION | 10 | REPEAT OR HYPERLOGLOG | 32 | AUTO |
ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-55622: DML, ALTER and CREATE UNIQUE INDEX operations are not allowed on table "SCOTT"."SYS_FBA_TCRV_83287"
set lines 155 col TABLE_NAME for a30 col OWNER_NAME for a30 col FLASHBACK_ARCHIVE_NAME for a30 col ARCHIVE_TABLE_NAME for a30 col STATUS for a30 SELECT * FROM DBA_FLASHBACK_ARCHIVE_TABLES WHERE OWNER_NAME=upper('SCOTT');
set trimspool on set heading off set feedback off set echo off set verify off spool disable_flb_archive.sql SELECT 'spool disable_flb_archive.log' FROM dual; SELECT 'alter table ' || owner_name || '.' || table_name || ' no flashback archive;' FROM DBA_FLASHBACK_ARCHIVE_TABLES WHERE OWNER_NAME=upper('SCOTT'); SELECT 'exit' FROM dual; exit
sqlplus / as sysdba @gen_disable_fda.sql
alter table SCOTT.EMP no flashback archive;
select SYS_CONTEXT('userenv','con_name') "container name", SYS_CONTEXT('userenv','con_id') "container id", SYS_CONTEXT('userenv','CURRENT_SCHEMA') "Current schema", SYS_CONTEXT('userenv','SID') "SID" FROM DUAL container name container id Current schema SID -------------------- -------------------- ------------------------------ ----- VEGDB01 3 SCOTT 362 --Update a the table rows: update emp set sal=1000; 14 rows updated.
select SYS_CONTEXT('userenv','con_name') "container name", SYS_CONTEXT('userenv','con_id') "container id", SYS_CONTEXT('userenv','CURRENT_SCHEMA') "Current schema", SYS_CONTEXT('userenv','SID') "SID" FROM DUAL; container name container id Current schema SID -------------------- -------------------- ------------------------------ ----- VEGDB01 3 SCOTT 130 --Update the same rows as in session# 1: update emp set sal=2000;
sqlplus / as sysdba @$ORACLE_HOME/rdbms/admin/utllockt.sql
WAITING_SESSION LOCK_TYPE MODE_REQUESTED MODE_HELD LOCK_ID1 LOCK_ID2 ----------------- ----------------- --------------- ------------ ----------------- ----------------- 362 None 130 Transaction Exclusive Exclusive 524308 17836
SELECT sess.sid,sess.serial#,sess.sql_id,s.plan_hash_value, s.child_number,sess.client_info,substr(sql_text,1,30) "sql text",sess.program,sess.pq_status, decode(sess.blocking_session_status,'VALID','blocked', 'NO HOLDER','Not blocked') "blocked?", sess.blocking_session "blocking session SID",sess.event FROM V$SESSION sess inner join v$sql s on (sess.sql_id = s.sql_id) WHERE sess.SID IN (130) and sess.sql_child_number = s.child_number;
SID | SERIAL# | SQL_ID | PLAN_HASH_VALUE | sql text | PROGRAM | PQ_STATUS | blocked? | blocking session SID | EVENT |
---|---|---|---|---|---|---|---|---|---|
130 |
9755 |
1gpj28ptjj43p | 1494045816 |
update emp set sal=2000 | sqlplus@ | ENABLED | blocked | 362 |
enq: TX - row lock contention |