Tuesday, October 27, 2015

Oracle AQ Buffered Queues

Oracle AQ Buffered Queues


Set Up the environnement to use SQL*Plus and to connect as SYSDBA
Create a DEMO user and a User Defined Type in the 2 databases
Create a database link between the source and the destination databases
Create and start queues
Create a subscribers on the source queue and schedule propagation to the destination queue
Create an enqueue procedure in the source database
Create a dequeue procedure in the destination database
Enqueue a message on one end and dequeue it on the other end
Clean Up the environment
You can start right away...
Set Up the environnement to use SQL*Plus and to connect as SYSDBA

To begin, you'll set the SQL*Plus variables that follow:
sourcegdb defines the global_name AND the network alias of the source database.
We assume global_names=true, even if that's not strictly mandatory.
It helps to make things more readable. Make sure you have the aliases setup everywhere and they match the database global names.
destgdb defines the global_name AND the network alias of the destination database.
source_user and dest_user define names of SYSDBA users on the source and on the destination databases.
source_pwd and dest_pwd define the passwords of the corresponding source_user and dest_user.
accept sourcegdb default 'BLACK' -
prompt "Enter the Source Database Global Name                [BLACK]: "

accept destgdb   default 'WHITE' -
prompt "Enter the Destination Database Global Name           [WHITE]: "

accept source_user default 'sys'  -
prompt "Enter the Destination SYSDBA user                      [sys]: "

accept source_pwd  default 'change_on_install'  -
prompt "Enter the Destination SYSDBA password    [change_on_install]: "

accept dest_user default 'sys'  -
prompt "Enter the Destination SYSDBA user                      [sys]: "

accept dest_pwd  default 'change_on_install'  -
prompt "Enter the Destination SYSDBA password    [change_on_install]: "
Create a User DEMO and a User Defined Type in the 2 databases

To go on with the example, you'll need to create the DEMO user in the 2 databases and create a type
you'll use to send and receive messages. The script below creates those users and types.
Note:
For this example, we assume there is no user named DEMO. We also assume the 2 tablespaces USERS and TEMP exist in the databases.
There is no need for any of the database to run in ARCHIVELOG mode.

connect &&source_user/&&source_pwd@&&sourcegdb as sysdba

create user demo
identified by demo
default tablespace users
temporary tablespace temp;

grant connect, resource, dba to demo;
grant execute on dbms_aq to demo;
grant execute on dbms_aqadm to demo;

connect &&dest_user/&&dest_pwd@&&destgdb as sysdba

create user demo
identified by demo
default tablespace users
temporary tablespace temp;

grant connect, resource, dba to demo;
grant execute on dbms_aq to demo;
grant execute on dbms_aqadm to demo;

connect demo/demo@&&sourcegdb

create type mytype as object (
        id     number
      , field1 varchar2(4000)
      , field2 varchar2(4000));
/

connect demo/demo@&&destgdb

create type mytype as object (
        id     number
      , field1 varchar2(4000)
      , field2 varchar2(4000));
/
Create a database link between the source and the destination databases

To start the propagation job, you'll need the source database to connect to the destination database. Create and test a database link for that purpose:
connect demo/demo@&&sourcegdb

create database link &&destgdb
 connect to demo
 identified by demo
 using '&&destgdb';

select * from dual@&&destgdb;
Create and start queues

Then, create and start the queues:
connect demo/demo@&&destgdb

begin
dbms_aqadm.create_queue_table(
     'myqueue_table'
   , 'mytype'
   , multiple_consumers => true);
end;
/

begin
dbms_aqadm.create_queue(
     'myqueue'
   , 'myqueue_table');
end;
/

begin
dbms_aqadm.start_queue('myqueue');
end;
/

connect demo/demo@&&sourcegdb

begin
dbms_aqadm.create_queue_table(
     'myqueue_table'
   , 'mytype'
   , multiple_consumers => true);
end;
/

begin
dbms_aqadm.create_queue(
     'myqueue'
   , 'myqueue_table');
end;
/

begin
dbms_aqadm.start_queue('myqueue');
end;
/
Create a subscribers on the source queue and schedule propagation to the destination queue

The next step consists in adding the subscribers that match the destination queue, to the source queue.
In this example, we add 2 subscribers because we will eventually dequeue the messages from 2 separate programs
(or for 2 distinct purposes). Once done, check the queues are compatibles and schedule the QUEUE to QUEUE propagation.
dba_queue_schedules provides detailed informations about what is scheduled:
connect demo/demo@&&sourcegdb

begin
dbms_aqadm.add_subscriber(
     queue_name => 'myqueue'
   , subscriber => sys.aq$_agent('RED','demo.myqueue@&&destgdb',null)
   , queue_to_queue => true
   , delivery_mode  => dbms_aqadm.buffered);
end;
/

begin
dbms_aqadm.add_subscriber(
     queue_name => 'myqueue'
   , subscriber => sys.aq$_agent('BLUE','demo.myqueue@&&destgdb',null)
   , queue_to_queue => true
   , delivery_mode  => dbms_aqadm.buffered);
end;
/

set serveroutput on

declare
rc binary_integer;
begin
dbms_aqadm.verify_queue_types(
     src_queue_name  => 'myqueue'
   , dest_queue_name => 'demo.myqueue'
   , destination     => '&&destgdb'
   , rc => rc);
dbms_output.put_line('If result is 1, it''s OKAY: '||rc);
end;
/

begin
dbms_aqadm.schedule_propagation(
     queue_name => 'myqueue'
   , destination => '&&destgdb'
   , destination_queue => 'demo.myqueue');
end;
/

set pages 1000
select schema
   , qname
   , destination
   , start_time
   , latency
   , schedule_disabled
   , session_id
   , total_number
   , failures
   , last_error_msg
   , message_delivery_mode
from dba_queue_schedules;
Create an enqueue procedure in the source database

Create an enqueue procedure demo_enqueue, that enqueues a message in the buffered part of the queue:
connect demo/demo@&&sourcegdb

create or replace procedure demo_enqueue(p_mytype mytype) is
enqueue_options     DBMS_AQ.enqueue_options_t;
message_properties  DBMS_AQ.message_properties_t;
recipients          DBMS_AQ.aq$_recipient_list_t;
message_handle      RAW(16);
begin
enqueue_options.visibility := dbms_aq.immediate;
enqueue_options.delivery_mode := dbms_aq.buffered;
dbms_aq.enqueue(
   queue_name         => 'MYQUEUE',
   enqueue_options    => enqueue_options,
   message_properties => message_properties,
   payload            => p_mytype,
   msgid              => message_handle);
commit;
end;
/
Create a dequeue procedure in the destination database

demo_dequeue dequeues messages from the destination queue based on the consumer name:
connect demo/demo@&&destgdb

select * from aq$myqueue_table_S;

set serveroutput on

create or replace procedure demo_dequeue(p_consumer varchar2)
is
dequeue_options       dbms_aq.dequeue_options_t;
message_properties    dbms_aq.message_properties_t;
message_handle        RAW(16);
v_mytype              mytype;
no_messages           exception;
pragma exception_init(no_messages, -25228);
begin
dequeue_options.wait          := dbms_aq.no_wait;
dequeue_options.consumer_name := p_consumer;
dequeue_options.navigation    := dbms_aq.first_message;
dequeue_options.visibility    := dbms_aq.immediate;
dequeue_options.delivery_mode := dbms_aq.buffered;
loop
begin
dbms_aq.dequeue(
   queue_name         => 'myqueue',
   dequeue_options    => dequeue_options,
   message_properties => message_properties,
   payload            => v_mytype,
   msgid              => message_handle);
dbms_output.put_line('---------------------------------------------------------');
dbms_output.put_line('Message for Consumer "'||p_consumer||'": ');
dbms_output.put_line('ID    :'||to_char(v_mytype.id));
dbms_output.put_line('FIELD1:'||v_mytype.field1);
dbms_output.put_line('FIELD2:'||v_mytype.field2);
dbms_output.put_line('---------------------------------------------------------');
dequeue_options.navigation := dbms_aq.next_message;
end;
end loop;
exception
when no_messages then
  dbms_output.put_line('No more messages');
  commit;
end;
/
Enqueue a message on one end and dequeue it on the other end

You are ready to test your case. Enqueue a message and check you get the messages for the 2 subscribers:
connect demo/demo@&&sourcegdb
set serveroutput on
declare
v_mytype mytype;
begin
v_mytype := mytype(1, 'BLUE AND RED','Red And Blue');
demo_enqueue(v_mytype);
end;
/

select * from aq$myqueue_table;


connect demo/demo@&&destgdb

select * from aq$myqueue_table;

set serveroutput on
exec demo_dequeue('BLUE')
exec demo_dequeue('RED')
Note:
aq$myqueue_table help to monitor the messages. The propagation has been set without any time means that the messages are always sent from the source to the destination; the latency (default to 60 in that case), is the only thing that can slightly impact the time needed for the message to be available for the consumers
Clean Up the environment

You are done! Before you leave, suppress the AQ propagation schedule, the queues and the DEMO users:
connect &&source_user/&&source_pwd@&&sourcegdb as sysdba

begin
dbms_aqadm.UNSCHEDULE_PROPAGATION(
                  queue_name        => 'demo.myqueue'
                , destination       => '&&destgdb'
                , destination_queue => 'DEMO.MYQUEUE');
end;
/

exec dbms_aqadm.drop_queue_table('demo.myqueue_table',TRUE)

drop user demo cascade;

select * from dba_queue_schedules;

connect &&dest_user/&&dest_pwd@&&destgdb as sysdba

exec dbms_aqadm.drop_queue_table('demo.myqueue_table',TRUE)

drop user demo cascade;

Friday, October 23, 2015

Master Note for AQ Queue Monitor Process (QMON)


Master Note for AQ Queue Monitor Process (QMON) (Doc ID 305662.1)

Details
  Queue Monitor Processes - QMON
  Pre-10.1 QMON Architecture
  10.1 onwards QMON Architecture
  QMON coordinator
  QMON tasks
  QMON Server Processes
  Significance of the AQ_TM_PROCESSES Parameter in 10.1 onwards
  Common Observations / Issues linked to QMON
  PROCESSED Messages not being removed
  TM Operations : Delay, Expiration, Retention not working as expected
  Delay / WAIT Period Incorrect after Daylight Saving Time change
  High CPU usage from QMON Coordinator process
  Unexpected Growth in Queue Table Objects
  QMON Space Reclamation / Coalesce Queues
  Collecting Diagnostic Information for Troubleshooting QMON issues
References
APPLIES TO:

Oracle Database - Standard Edition - Version 9.2.0.1 to 11.2.0.3 [Release 9.2 to 11.2]
Oracle Database - Enterprise Edition - Version 8.1.7.0 to 12.1.0.2 [Release 8.1.7 to 12.1]
Information in this document applies to any platform.
PURPOSE

In this article, we will discuss the following

1. The Queue Monitor Coordinator process (QMNC) , the Queue Monitor Server Processes (QXXX) and Task Operations which can be assigned to these processes. Collectively these processes are named the Queue Monitor processes or QMON processes.

2. Known issues which affect these processes.

3. How to collect useful diagnostic information when problems arise with them.

SCOPE

Database administrators of Advanced Queueing (AQ) and Streams databases.

DETAILS

Queue Monitor Processes - QMON

QMON processes are connected with Oracle Streams, Advanced Queueing (AQ), and a variety of other Database products which monitor and maintain system and user-owned AQ persistent and buffered objects. For example, the Oracle job scheduler uses AQ and serves as a client to various database components to allow operations to be coordinated at scheduled times and intervals. Similarly, Oracle Grid Control relies on AQ for its Alerts and Service Metrics and database server utilities such as datapump now use AQ. Furthermore, Oracle Applications has and will continue to use AQ.

QMON processes are associated with the mechanisms for message expiration, retry, delay, maintaining queue statistics, removing PROCESSED messages from a queue table and updating the dequeue IOT as necessary.

QMON has a part to play in both permanent and buffered message processing.

If a qmon process should fail, this should not cause the instance to fail. This is also the case with job queue processes.

QMON itself operates on queues but does not use a database queue for its own processing of tasks and time based operations.

QMON can be envisaged as a number of discrete tasks which are run by Queue Monitor processes or servers.

Pre-10.1 QMON Architecture

Prior to 10.1 the number of queue monitor processes is explicitly controlled via the dynamic initialisation parameter AQ_TM_PROCESSES. If this parameter is set to a non-zero value X, Oracle creates that number of QMNX processes starting from ora_qmn0_SID (where SID is the identifier of the database) up to ora_qmnX_SID ; if the parameter is not specified or is set to 0, then the QMON processes are not created. There can be a maximum of 10 QMON processes running on a single instance. For example the parameter can be set in the init.ora as follows :

aq_tm_processes=1

or set dynamically via

alter system set aq_tm_processes=1;

10.1 onwards QMON Architecture

Beginning with release 10.1, the architecture of the QMON processes was changed to an automatically controlled coordinator/slave architecture. The Queue Monitor Coordinator, ora_qmnc_SID, dynamically spawns server process named, ora_qXXX_SID Depending on the system load this will be up to a maximum of 10 per instance up to and including version 11.1 and 40 per instance from 11.2 onwards.

QMON coordinator

The coordinator is responsible for allocating tasks to QMON processes. Some of these tasks are scheduled, time based activities whereas others are event driven.

In the case of buffered messaging in a RAC environment, if a RAC instance should fail, an existing QMON server process will move ownership of the queues, where necessary to a new owning instance. This would be relevant in a Streams configuration for example where a primary / secondary instance is defined. As an aim of Streams is to maintain messages in memory when an instance is down, the processing of buffered messages has to be done on a surviving instance (a related Capture or Apply process would also need to be relocated); once the owning instance has been changed, QMON can then resume activity on the buffered queue on this instance.

Starting with 11.2.0.1, the coordinator information is visible in GV$QMON_COORDINATOR_STATS.

QMON tasks

Tasks relate to a specific action which will be allocated to a QMON server process.

In 11.2.0.1, the view : GV$QMON_TASK_STATS shows all the tasks available at this version in addition to whether any errors may have been encountered in the task processing. The view shows details relating to the following tasks (based on columns : task_name and remark - as detailed in the Oracle Reference Guide) :

Task Name Remark
QMON_PERSISTENT_TM Persistent messages time manager activity
QMON_SPILL Buffered messages spilling
QMON_DEALLOC_SPILLED Spilled messages memory deallocation
QMON_DELETE_SPILLED Dequeued spilled messages deletion
QMON_PURGE Not specified
QMON_COMPUTE_ACKS Acknowledgement update for a queue locally
QMON_FLUSH_STATS Replay info table update
QMON_PROCESS_IPC IPC message send and receive for queue operations
QMON_RECOVER_SPILLED Spilled messages recovery on startup
QMON_PROP_MSGDELETE Acknowledged buffered messages deletion
QMON_JOBCACHE_REPARTITION  Queue table ownership change
QMON_PURGE_SPILLED Purge spilled messages at startup
QMON_BUFFERED_TM_COORD Buffered messages time manager activity check
QMON_BUFFERED_TM Buffered messages time manager activity
QMON_QUEUE_SERVICE_START Start queue services at startup Start queue services at startup
QMON_PURGE_REGISTRATION Notification registration purge
QMON_RECOVER_EMON EMON recovery at startup
QMON_ORPHANED_MSGDELETE Orphaned messages deletion Orphaned messages deletion
QMON_SEND_ALTEROWNER Non-owner persistent time manager activity send to owner
QMON_NONDURSUB_SESS_DEL Session end nondurable subscriber delete
QMON_NONDURSUB_INST_DEL Instance end Nondurable subscriber delete
QMON_DELETE_DEADREG Notification delete registrations of dead locations
Note : Earlier versions may not have implemented all of the above .

The task list gives an impression of those operations the QMON process is responsible for. It can be gleaned that a significant number of the above are associated with activities such as cleanout of messages and housekeeping activities, i.e. it is more efficient on the performance of the foreground Application AQ process which is performing enqueue / dequeue operations that cleanout operations be handled in the background . TM (Time Management : delay , retry delay, expiration , retention) related activity is also handled by QMON server processes. e.g., when an application enqueues a message with a delay period the message will only become available for dequeue once the delay period has elapsed and QMON has changed the state of the message to READY.

In 11.2.0.1, the view : GV$QMON_TASKS gives an indication of the tasks which are running or have been scheduled by QMON.


Some tasks can only be run on a single instance for a queue such as might be the case with buffered messaging ; others can be run (not at the same time) across multiple instances by different qmon processes. Some tasks are categorised as repeatable operations and are scheduled to run periodically; others are viewed as one time operations with no schedule - as detailed in GV$QMON_TASKS.

QMON Server Processes

These are Processes or Servers at the OS level which are associated with task work activities scheduled by the coordinator.

In 11.2.0.1, the view : GV$QMON_SERVER_STATS presents an indication of the server processes which are active.

@Time Manager Related Monitoring Please note that that view : X$KWQMNJIT which shows

@ time based related
Significance of the AQ_TM_PROCESSES Parameter in 10.1 onwards

For version 10.1 onwards it is no longer necessary to set AQ_TM_PROCESSES when Oracle Streams AQ or Streams is used. However, if you do specify a value, then that value is taken into account but the number of processes can still be auto-tuned and so the number of running qXXX processes can be different from what was specified by AQ_TM_PROCESSES.

It should be noted that if AQ_TM_PROCESSES is explicitly specified then the process(es) started will only maintain persistent messages. For example if aq_tm_processes=1 then at least one queue monitor slave process will be dedicated to maintaining persistent messages. Other process can still be automatically started to maintain buffered messages. Up to and including version 11.1 if you explicitly set aq_tm_processes = 10 then there will be no processes available to maintain buffered messages. This should be borne in mind in environments which use Streams replication and from 10.2 onwards user enqueued buffered messages.

In addition you should never disable the Queue Monitor processes by setting aq_tm_processes=0 on a permanent basis. As can be seen above, disabling will stop all related processing in relation to tasks outlined. This will likely have a significant affect on operation of queues - PROCESSED messages will not be removed and any time related, TM actions will not succeed ; AQ objects will grow in size.

To check whether auto-tuning is enabled or aq_tm_processes=0 do the following:

connect / as sysdba

set serveroutput on

declare
mycheck number;
begin
select 1 into mycheck from v$parameter where name = 'aq_tm_processes' and value = '0' and (ismodified != 'FALSE' OR isdefault = 'FALSE');
if mycheck = 1 then
dbms_output.put_line('The parameter ''aq_tm_processes'' is explicitly set to 0!');
end if;
exception when no_data_found then
dbms_output.put_line('The parameter ''aq_tm_processes'' is not explicitly set to 0.');
end;
/
The parameter should not be set to 0 explicitly. If it is, then it is recommended to unset the parameter. However, this requires bouncing the database. In the meantime, if the database cannot be immediately bounced, the recommended value to set it to is '1', and this can be done dynamically:

connect / as sysdba
alter system set aq_tm_processes = 1;
In 11.2.0.3 onwards the 'real' default value of 1 is exposed in v$parameter which avoids confusion about whether auto-tuning is disabled or not.

To unset the parameter:

When using a pfile:

Comment out or remove the aq_tm_processes entry, and restart the database.

When using a spfile:

connect / as sysdba
alter system reset aq_tm_processes scope=spfile sid='*';
and restart the database.

Common Observations / Issues linked to QMON

The following outlines a number of commonly observed issues attributable to certain aspects of QMON operation or which may have an affect on QMON. Some cases outline specific steps to resolve and issue or detail steps to run to avoid issues connected with the issue.

Pertinent references are detailed with the intention of providing relevant context into what is being discussed.

PROCESSED Messages not being removed

If processed messages are not being cleaned out of queues once all subscribers have dequeued the message, this would suggest that QMON is not operating as expected : is the operation occurring at all or is it taking considerably longer than expected for this to occur.

This consequence of this may be the growth of queue table related objects.

Useful related references are :

Note 251737.1 PROCESSED Messages remain in Queue Table after a Successful Dequeue

Note 378247.1 PROCESSED Messages not removed from Queue Table in a RAC database after Reconfiguration

Note 752708.1 Intermittently PROCESSED Messages are not removed from Queue Tables by the QMON Processes.

TM Operations : Delay, Expiration, Retention not working as expected

Are any of these Time Manager related features being used . The deferred processing of messages in these cases may require more processing than necessary . Is high CPU being observed which might suggest that something else is behind the problem. Something to consider as a general rule is that high CPU from a process might be typically connected with high buffer gets suggesting that a large object is being accessed, possibly with a Full Table Scan. In such a situation an AWR report and or 10046 / level 12 trace (as detailed below can identify the object) can identify the object. tkprof can then be used to summarise the exection plan as well as statistic information such as buffers accessed. Using retention has the affect of keeping messages for a longer period than they would be otherwise with the obvious knock on affect that queue table related objects will be larger.

Useful related references are as follows :

Note 341133.1 Messages not changed from Wait To Ready State in a RAC database

Note 343282.1 CPU Consumption Of Queue Monitor Processes Increases when using Retention

Note 464514.1 Messages Enqueued With a Delay Specified to an Advanced Queue in a RAC Database Are Not Dequeued Immediately After the Delay Expires

Note 732743.1 Qmon Processes Are Not Removing Processed Messages or changing the state of WAITING messages.



Delay / WAIT Period Incorrect after Daylight Saving Time change

Following a change in DST, TM based activities may not occur when expected. The enq_time may not as expected and given that the wait time or delay is calculated relative to the enq_time this will have affect on the operation. The related fix referenced in the notes below does correct QMON activity.

This is outlined in

Note 429630.1  A Dequeue Condition fails to work properly after a Daylight Savings Time Change

and

Note 429681.1 Casting AQ$QUEUE_TABLE Enqueue and Dequeue Time Values To SESSIONTIMEZONE causes Reporting and Message Processing issues.

High CPU usage from QMON Coordinator process

Prior to 11.2 ensure that aq_tm_processes is not set to 10. In 11.2 onwards ensure that aq_tm_processes is not set to 10.  All the following refer to this same type of issue which manifests itself as high CPU from the Coordinator : Note 393781.1 , Note:604246.1 and Note:738873.1 when aq_tm_processes has been explicitly set to 10 in 10.1 to 11.1 versions.

Unexpected Growth in Queue Table Objects

First of all please refer to section : QMON Space Reclamation / Coalesce Queues.

QMON should perform periodic clean out of single consumer queue table indexes and coalesce multi consumer IOTs to ensure that space is reclaimed for AQ objects. If this does not work as expected, this can cause growth in these objects when there are actually few messages in the associated queues.

An initial analysis would be to consider enqueue / dequeue activity as well as how many references there are to messages in the queue before then determining the space used by the related objects :

- what is the throughput of messages in the queue - X messages per hour;
- are any of the TM features : delay, retry delay , expiration or retention being used;
- how many messages are currently in the queue (refer to queue table) :

select count(*), msg_state from aq$_queue_table group by msg_state;
select count(*) from aq$_queue_table_i;
select count(*) from aq$_queue_table_l; (new in 11.2.0.1)
select count(*) from aq$_queue_table_h;
select count(*) from aq$_queue_table_t;
select count(*) from aq$_queue_table_p; (optional / spill / Streams related)
select count(*) from aq$_queue_table_d; (optional / spill / Streams related)
- then, for each of the above and their associated IOTs, determine the related space usage :

select sum(bytes)/1024/1024 MB from user_segments where segment_name='';

The above is for a multi consumer queue ; a single consumer queue is simpler to look at as there is only the queue table and related indexes.

Note : If Streams related objects are large , this might be a valid Application issue , suggesting for example that Streams has spilled due to memory pressure possibly indicating some other problem.

If an IOT is particular are large, the following references may be useful :

Note 394713.1 Index SYS_IOT_TOP  on History IOT is very large / Qmn uses high CPU

Note:267137.1 QMON does not perform space management operations on the dequeue IOT in Locally Managed Tablespaces using ASSM or when using FREELIST GROUPs

Note:238272.1 Procedure to Manually Purge Messages from a Single-Consumer Queue when QMON fails to do it efficiently

Note:271855.1 Procedure to manually coalesce all the IOTs/indexes associated with Advanced Queueing tables to maintain Enqueue/Dequeue performance and reduce QMON CPU usage and Redo generation.

QMON Space Reclamation / Coalesce Queues

This is linked directly to the potential growth in AQ related objects in section Unexpected Growth in Queue Table Objects. As discussed in Note 271855.1, QMON does not service all related queue objects correctly until 11.2

Please consult this note and implement the script in your environment since it is probable that queues will have been created in ASSM tablespaces. As well as the space usage implications of this issue, the effect of implementing this procedure will likely be to improve the performance and effectiveness of QMON.

Collecting Diagnostic Information for Troubleshooting QMON issues

If the issue is not one which can be easily understood and addressed in the section Common Observations / Issues linked to QMON then in an ideal situation troubleshooting any issue is easier to progress with a testcase.

In the absence of this the following are some useful diagnostic steps for troubleshooting QMON issues. Typically this will be a situation in which the QMON process(es) are consuming a large amount of CPU or processed messages are not being removed.

1. For CPU consumption issues sql trace the QMON process in question by doing the following

Determine the pid of the Queue Monitor process (either qmnc or q00*), call it X

sqlplus / as sysdba
oradebug setospid X
oradebug unlimit
oradebug Event 10046 trace name context forever, level 12
--Generate trace for 20 minutes
oradebug Event 10046 trace name context off

Tkprof the raw sql trace file by following Note 232443.1. Provide both the raw trace file and tkprof output to Oracle Support.

2. For issues where a queue table is not being serviced in some way then the following may be useful:

Determine the pid of the Queue Monitor processes (either qmnc or q00*), call them X, Y, etc.

sqlplus / as sysdba;
oradebug setospid X
oradebug unlimit
oradebug Event 10046 trace name context forever, level 12
oradebug Event 10850 trace name context forever, level 10
--10852 only applies to 10.1 onwards
oradebug Event 10852 trace name context forever, level 32
--Generate trace for 20 minutes
oradebug Event 10046 trace name context off
oradebug Event 10850 trace name context off
oradebug Event 10852 trace name context off

Repeat this tracing for all the running Queue Monitor Coordinator and Queue Monitor slave processes.

Tkprof the raw sql trace file by following Note 232443.1. Provide both the raw trace file and tkprof output to Oracle Support.

3. For investigating issues with QMON processes in a RAC environment then the following additional trace events are also useful

oradebug Event 10852 trace name context forever, level 128

this traces queue table ownership changes. This level can be combined with the level 32 set for single instance environment for a level of 160. In addition to this event 26700 level 256 which can be set via

alter system set events '26700 trace name context forever, level 256';

which traces inter-instance IPC communication between the QMON processes.

Note that event 26700 has a different meaning in 9.2 and should not be used.







Still have questions ?

To discuss this information further with Oracle experts and industry peers, we encourage you to review, join or start a discussion via My Oracle Support GoldenGate, Streams and Distributed Database Community
Enjoy a short Video about Oracle´s Support Communities - to quickly understand it´s benefits for you right now (http://bcove.me/tlygjitz)

The goal of this community is to exchange knowledge and concepts about Oracle Streams Advanced Queuing (AQ) and distributed databases, with special consideration for the components listed below:
  -     Distributed Databases
  -     Streams Replication and Advanced Queuing
  -     Advanced Replication
  -     XA

To provide feedback on this note, click on the Rate this document link above.
REFERENCES

NOTE:564663.1 - Queue Monitor Coordinator Process delays Database Opening due to Replication Queue Tables with Large HighWaterMark
NOTE:604246.1 - Queue Monitor Coordinator Process consuming 100% of 1 cpu
NOTE:729535.1 - ORA-00600 [1:Kwqvss], [2] reported by a Queue Monitor Slave Process causing a RAC instance to abort
NOTE:732743.1 - Queue Monitor (QMON) Processes Are Not Removing PROCESSED Messages or Changing the State of WAITING Messages in a RAC Cluster
NOTE:738873.1 - Queue Monitor Coordinator Cpu Consumption is High when AQ_TM_PROCESSES=10
NOTE:752708.1 - Intermittently PROCESSED Messages Are Not Removed from Queue Tables by the QMON Processes
NOTE:793632.1 - Restarting Dead Queue Monitor Process upgrade from 9.2 to 10.2
NOTE:208563.1 - Unexplained Log Activity In An "idle" Database On AQ$_QUEUE_TABLE_AFFINITIES and AQ$_QUEUE_TABLES Caused by QMNn Processes
NOTE:232443.1 - How to Identify Resource Intensive SQL ("TOP SQL")
NOTE:233101.1 - Queue Monitor process Memory Consumption increases due to a Leak
NOTE:251737.1 - PROCESSED Messages remain in Queue Table after a Successful Dequeue
NOTE:267137.1 - QMON does not perform space management operations on the dequeue IOT in Locally Managed Tablespaces using ASSM or when using FREELIST GROUPs
NOTE:271855.1 - Procedure to Manually Coalesce All the IOTs / Indexes Associated with Advanced Queueing Tables to Maintain Enqueue / Dequeue Performance; Reduce QMON CPU Usage and Redo Generation
NOTE:271955.1 - Repeated 'Restarting dead background process QMNX' message in the Alert Log
NOTE:341133.1 - Messages not changed from Wait To Ready State in a RAC database
NOTE:343282.1 - CPU Consumption Of Queue Monitor Processes Increases when using Retention
NOTE:357053.1 - Queue Table Ownership not Falling back to the Primary Instance in a RAC environment
NOTE:378247.1 - PROCESSED Messages not removed from Queue Table in a RAC database after Reconfiguration
NOTE:393781.1 - QMNC Process Spins / Exhibits High CPU When aq_tm_processes=10
NOTE:394713.1 - Index SYS_IOT_TOP_ on a Queue Table History IOT Is Very Large and the Queue Monitor Process Is Consuming CPU
NOTE:395137.1 - Repeated : Restarting dead background process QMNC recorded in the alert.log file
NOTE:429630.1 - A Dequeue Condition fails to work properly after a Daylight Savings Time Change
NOTE:429681.1 - Casting AQ$QUEUE_TABLE Enqueue and Dequeue Time Values To SESSIONTIMEZONE causes Reporting and Message Processing issues
NOTE:453392.1 - RAC Node Startups Delayed Repartitioning Queue Tables after Failover
NOTE:458912.1 - 'IPC Send Timeout Detected' errors between QMON Processes after RAC reconfiguration
NOTE:464514.1 - Messages Enqueued With a Delay Specified to an Advanced Queue in a RAC Database Are Not Dequeued Immediately After the Delay Expires


Wednesday, September 23, 2015

INTERVAL Partition Autp Deletion and addition

create table test_part
(
CREATED_DT            DATE
)
PARTITION BY RANGE (CREATED_DT)
INTERVAL(numtodsinterval(7,'day'))
(
PARTITION PART_01 VALUES LESS THAN('01-Sep-2015'),
PARTITION PART_02 VALUES LESS THAN('08-Sep-2015'),
PARTITION PART_03 VALUES LESS THAN('15-Sep-2015'),
PARTITION PART_04 VALUES LESS THAN('22-Sep-2015'),
PARTITION PART_05 VALUES LESS THAN('29-Sep-2015'),
PARTITION PART_06 VALUES LESS THAN('06-Oct-2015')
);
insert into test_part values('10-oct-2015');
declare
  i NUMBER(3):=1;
begin
  for x in (select partition_name
              from user_tab_partitions
              where table_name = 'TEST_PART' and partition_name not like 'PART_%')
  loop
       execute immediate ('alter table TEST_PART rename partition '||x.partition_name||' to PART_'||i);
        i:=i+1;              
  end loop;
end;
/

declare
  dt date;
begin
  for x in (select partition_name, high_value
              from user_tab_partitions
              where table_name = 'TEST_PART')
  loop
    execute immediate 'select '||x.high_value||' from dual' into dt;
    if dt < sysdate -20 then
      dbms_output.put_line('ALTER TABLE TEST_PART DROP PARTITION  '||x.partition_name);
      execute immediate ('ALTER TABLE TEST_PART DROP PARTITION  '||x.partition_name);
    end if;
  end loop;
end;
/
select partition_name, high_value from user_tab_partitions
where table_name = 'TEST_PART' and partition_name not like 'E__%';

Thursday, June 4, 2015

SQL Tuning query

Unused Index
SELECT
OBJECT_NAME(i.[object_id]) AS [Table Name] ,
i.name
FROM
sys.indexes AS i
INNER JOIN
sys.objects AS o ON i.[object_id] = o.[object_id]
WHERE
i.index_id NOT IN ( SELECT ddius.index_id FROM sys.dm_db_index_usage_stats AS ddius WHERE ddius.[object_id] = i.[object_id] AND i.index_id = ddius.index_id AND database_id = DB_ID() )
AND
o.[type] = 'U'
ORDER BY
OBJECT_NAME(i.[object_id]) ASC;

Missing Index

SELECT user_seeks * avg_total_user_cost * ( avg_user_impact * 0.01 )
AS [index_advantage] ,
dbmigs.last_user_seek ,
dbmid.[statement] AS [Database.Schema.Table] ,
dbmid.equality_columns ,
dbmid.inequality_columns ,
dbmid.included_columns ,
dbmigs.unique_compiles ,
dbmigs.user_seeks ,
dbmigs.avg_total_user_cost ,
dbmigs.avg_user_impact
FROM sys.dm_db_missing_index_group_stats AS dbmigs WITH ( NOLOCK )
INNER JOIN sys.dm_db_missing_index_groups AS dbmig WITH ( NOLOCK )
ON dbmigs.group_handle = dbmig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS dbmid WITH ( NOLOCK )
ON dbmig.index_handle = dbmid.index_handle
WHERE dbmid.[database_id] = DB_ID()
ORDER BY index_advantage DESC;

High I/O Procedure

SELECT
p.name AS [SP Name],
deps.cached_time,
deps.total_logical_reads AS [TotalLogicalReads],
deps.total_logical_writes as [TotalLogicalWrites],
deps.total_physical_reads as [TotalPhysicalReads],
(deps.total_logical_reads + deps.total_logical_writes + deps.total_physical_reads) as [Total_IO_Impact],
deps.total_elapsed_time as [TotalElapsedTime],
deps.execution_count as [ExecutionCount]
FROM
sys.procedures AS p
INNER JOIN
sys.dm_exec_procedure_stats AS deps
ON
p.[object_id] = deps.[object_id]
WHERE
deps.database_id = DB_ID()
ORDER BY
(deps.total_logical_reads + deps.total_logical_writes + deps.total_physical_reads) DESC;

--TOP 10 Highest IO Statements
SELECT
CASE WHEN deqs.statement_start_offset = 0 AND deqs.statement_end_offset = -1 THEN '-- see objectText column--' ELSE '-- query --' + CHAR(13) + CHAR(10) + SUBSTRING(execText.text, deqs.statement_start_offset / 2, ( ( CASE WHEN deqs.statement_end_offset = -1 THEN DATALENGTH(execText.text) ELSE deqs.statement_end_offset END ) - deqs.statement_start_offset ) / 2) END AS queryText,
deqs.total_logical_reads AS [TotalLogicalReads],
deqs.total_logical_writes as [TotalLogicalWrites],
deqs.total_physical_reads as [TotalPhysicalReads],
(deqs.total_logical_reads + deqs.total_logical_writes + deqs.total_physical_reads) as [Total_IO_Impact],
deqs.total_elapsed_time as [TotalElapsedTime],
deqs.execution_count as [ExecutionCount]
FROM
sys.dm_exec_query_stats deqs
CROSS APPLY
sys.dm_exec_sql_text(deqs.plan_handle) AS execText
ORDER BY
(deqs.total_logical_reads + deqs.total_logical_writes + deqs.total_physical_reads) DESC ;

SELECT TOP 10 total_worker_time,
execution_count,
total_worker_time / execution_count AS [Avg CPU Time],
CASE WHEN deqs.statement_start_offset = 0 AND deqs.statement_end_offset = - 1
THEN '-- see objectText column--' ELSE '-- query --' + CHAR(13) +
CHAR(10) + SUBSTRING(execText.TEXT, deqs.statement_start_offset
/ 2, (
(
CASE WHEN deqs.statement_end_offset = - 1 THEN
DATALENGTH(execText.TEXT) ELSE
deqs.statement_end_offset END
) - deqs.statement_start_offset
) / 2) END AS queryText
FROM sys.dm_exec_query_stats deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) AS execText
ORDER BY deqs.total_worker_time DESC;

High Scan Index
SELECT TOP 10
OBJECT_NAME(ddius.[object_id], ddius.database_id) AS [object_name] ,
ddius.index_id ,
ddius.user_seeks ,
ddius.user_scans ,
ddius.user_lookups ,
ddius.user_seeks + ddius.user_scans + ddius.user_lookups AS user_reads,
ddius.user_updates AS user_writes ,
ddius.last_user_scan ,
ddius.last_user_update
FROM
sys.dm_db_index_usage_stats ddius
WHERE
ddius.database_id > 4 -- filter out system tables
AND
OBJECTPROPERTY(ddius.object_id, 'IsUserTable') = 1
AND
ddius.index_id > 0 -- filter out heaps
ORDER BY
ddius.user_scans DESC;

Over updated Index
SELECT OBJECT_NAME(ddius.[object_id]) AS [Table Name] ,
i.name AS [Index Name] ,
i.index_id ,
user_updates AS [Total Writes] ,
user_seeks + user_scans + user_lookups AS [Total Reads] ,
user_updates - ( user_seeks + user_scans + user_lookups )
AS [Difference]
FROM sys.dm_db_index_usage_stats AS ddius WITH ( NOLOCK )
INNER JOIN sys.indexes AS i WITH ( NOLOCK )
ON ddius.[object_id] = i.[object_id]
AND i.index_id = ddius.index_id
WHERE OBJECTPROPERTY(ddius.[object_id], 'IsUserTable') = 1
AND ddius.database_id = DB_ID()
AND user_updates > ( user_seeks + user_scans + user_lookups )
AND i.index_id > 1
ORDER BY [Difference] DESC ,
[Total Writes] DESC ,
[Total Reads] ASC ;

Lock Contention

SELECT OBJECT_NAME(ddios.object_id, ddios.database_id) AS object_name ,
i.name AS index_name ,
ddios.index_id ,
ddios.partition_number ,
ddios.page_lock_wait_count ,
ddios.page_lock_wait_in_ms ,
CASE WHEN DDMID.database_id IS NULL THEN 'N'
ELSE 'Y'
END AS missing_index_identified
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ddios
INNER JOIN sys.indexes i ON ddios.object_id = i.object_id
AND ddios.index_id = i.index_id
LEFT OUTER JOIN ( SELECT DISTINCT
database_id ,
object_id
FROM sys.dm_db_missing_index_details
) AS DDMID ON DDMID.database_id = ddios.database_id
AND DDMID.object_id = ddios.object_id
WHERE ddios.page_lock_wait_in_ms > 0
ORDER BY ddios.page_lock_wait_count DESC ;

Lock Escalation

SELECT OBJECT_NAME(ddios.[object_id], ddios.database_id) AS [object_name] ,
i.name AS index_name ,
ddios.index_id ,
ddios.partition_number ,
ddios.index_lock_promotion_attempt_count ,
ddios.index_lock_promotion_count ,
( 1.0 * ddios.index_lock_promotion_count
/ ddios.index_lock_promotion_attempt_count ) AS percent_success
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ddios
INNER JOIN sys.indexes i ON ddios.object_id = i.object_id
AND ddios.index_id = i.index_id
WHERE ddios.index_lock_promotion_count > 0
ORDER BY index_lock_promotion_count DESC ;

Locking and Blocking

SELECT
'[' + DB_NAME(ddios.[database_id]) + '].[' + su.[name] + '].[' + o.[name] + ']' AS [statement] ,
i.[name] AS 'index_name' ,
ddios.[partition_number] ,
ddios.[row_lock_count] ,
ddios.[row_lock_wait_count] ,
CAST (100.0 * ddios.[row_lock_wait_count] / ( ddios.[row_lock_count] ) AS DECIMAL(5, 2)) AS [%_times_blocked] ,
ddios.[row_lock_wait_in_ms] ,
CAST (1.0 * ddios.[row_lock_wait_in_ms]
/ ddios.[row_lock_wait_count] AS DECIMAL(15, 2))
AS [avg_row_lock_wait_in_ms]
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ddios
INNER JOIN sys.indexes i ON ddios.[object_id] = i.[object_id]
AND i.[index_id] = ddios.[index_id]
INNER JOIN sys.objects o ON ddios.[object_id] = o.[object_id]
INNER JOIN sys.sysusers su ON o.[schema_id] = su.[UID]
WHERE ddios.row_lock_wait_count > 0
AND OBJECTPROPERTY(ddios.[object_id], 'IsUserTable') = 1
AND i.[index_id] > 0
ORDER BY [avg_row_lock_wait_in_ms] DESC

Letch Wait

SELECT '[' + DB_NAME() + '].[' + OBJECT_SCHEMA_NAME(ddios.[object_id])
+ '].[' + OBJECT_NAME(ddios.[object_id]) + ']' AS [object_name] ,
i.[name] AS index_name ,
ddios.page_io_latch_wait_count ,
ddios.page_io_latch_wait_in_ms ,
( ddios.page_io_latch_wait_in_ms / ddios.page_io_latch_wait_count )
AS avg_page_io_latch_wait_in_ms
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ddios
INNER JOIN sys.indexes i ON ddios.[object_id] = i.[object_id]
AND i.index_id = ddios.index_id
WHERE ddios.page_io_latch_wait_count > 0
AND OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1
ORDER BY ddios.page_io_latch_wait_count DESC ,
avg_page_io_latch_wait_in_ms DESC;


Saturday, May 30, 2015

Spilt SQL Server Datafile to multiple files

Spilt SQL Server Datafile to multiple files

Check the Datafile and space used

Use AdventureWorks;
SELECT df.name ,df.size/128.0 - CAST(FILEPROPERTY(df.name, 'SpaceUsed') AS int)/128.0 AS AvailableSpaceInMB,
df.size/128.0 as CurrenSizeinMB,mf.size*8192/1024 AS InitialSizeinKB
FROM sys.database_files df join
sys.master_files mf on df.name = mf.name and database_id = DB_ID()
go


DBCC SHOWFILESTATS

Show the space information in the extents context.

Use AdventureWorks;
DBCC SHOWFILESTATS;


Check tables/index belong to which file group


select  t.name as TableName,
        i.name as IndexName,
        fg.name as FielGroup,
        i.type,
        i.type_desc,
        t.type,
        p.rows as Rows
    from sys.filegroups fg join sys.database_files df
        on fg.data_space_id = df.data_space_id join sys.indexes i
        on df.data_space_id = i.data_space_id join sys.tables t
        on i.object_id = t.object_id join sys.partitions p
    on t.object_id = p.object_id and i.index_id = p.index_id
    --where fg.name = 'primary' and t.type = 'U'
    order by rows desc

ADD new file group and new datafiles



USE [master]
GO
ALTER DATABASE [AdventureWorks] ADD FILEGROUP [SALES]
GO
ALTER DATABASE [AdventureWorks] ADD FILE
( NAME = N'Sales_Data', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\AdventureWorks_SalesData.ndf' , SIZE = 3072KB , FILEGROWTH = 1024KB ) TO FILEGROUP [SALES]
GO



Create/recreate the cluster index and place it into file group.


create the test table

SELECT *
INTO newsales
FROM sales.Individual;

CREATE CLUSTERED INDEX IX_CustomerID
    ON newsales (customerID);
GO
Check the filegroup size and the location of the filegroup

Use AdventureWorks;
SELECT df.name ,df.size/128.0 - CAST(FILEPROPERTY(df.name, 'SpaceUsed') AS int)/128.0 AS AvailableSpaceInMB,
df.size/128.0 as CurrenSizeinMB,mf.size*8192/1024 AS InitialSizeinKB
FROM sys.database_files df join
sys.master_files mf on df.name = mf.name and database_id = DB_ID()
go

select  t.name as TableName,
        i.name as IndexName,
        fg.name as FielGroup,
        i.type,
        i.type_desc,    
        t.type,
        p.rows as Rows
    from sys.filegroups fg join sys.database_files df
        on fg.data_space_id = df.data_space_id join sys.indexes i
        on df.data_space_id = i.data_space_id join sys.tables t
        on i.object_id = t.object_id join sys.partitions p
    on t.object_id = p.object_id and i.index_id = p.index_id
    where t.name='newsales'


Add new filegroup

USE [master]
GO
ALTER DATABASE [AdventureWorks] ADD FILEGROUP [SALES]
GO
ALTER DATABASE [AdventureWorks] ADD FILE
( NAME = N'Sales_Data', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\AdventureWorks_SalesData.ndf' ,
SIZE = 3072KB , FILEGROWTH = 1024KB ) TO FILEGROUP [SALES]
GO


Recreate the cluster on the different filegroup.

USE [AdventureWorks];
CREATE CLUSTERED INDEX IX_CustomerID
    ON newsales (customerID)
    WITH(
        DROP_EXISTING = ON
        -- ONLINE = ON
        )
    ON SALES
GO


DBCC Shrink file emptyfile

Another way to move the data to other files is via DBCC SHRINKFILE emptyfiles. This would only move the data between data files in the same file group.

ALTER DATABASE [AdventureWorks] ADD FILE
( NAME = N'AdventureWorks_Data_new1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\AdventureWorks_Data1.ndf' , SIZE = 3072KB , FILEGROWTH = 1024KB ) TO FILEGROUP [PRIMARY]
GO
ALTER DATABASE [AdventureWorks] ADD FILE
( NAME = N'AdventureWorks_Data_new2', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\AdventureWorks_Data2.ndf' , SIZE = 3072KB , FILEGROWTH = 1024KB ) TO FILEGROUP [PRIMARY]
GO


Lets use DBCC SHRINKFILE with emptyfile option to move the data.

USE [AdventureWorks];
DBCC SHRINKFILE ( AdventureWorks_Data,emptyfile);


We can use DBCC SHOWFILESTATS to monitor the extend move status

Friday, March 27, 2015

How to Migrate to different Endian Platform Using Transportable Tablespaces With RMAN


https://support.oracle.com/epmos/adf/images/t.gif

Click to add to Favorites
https://support.oracle.com/epmos/adf/images/t.gif
To BottomTo
https://support.oracle.com/epmos/adf/images/t.gif

https://support.oracle.com/epmos/adf/images/t.gif

APPLIES TO:

Oracle Database - Enterprise Edition - Version 10.1.0.2 to 12.1.0.1 [Release 10.1 to 12.1]
Information in this document applies to any platform.
******************* WARNING *************

Document 1334152.1 Corrupt IOT when using Transportable Tablespace to HP from different OS
Document 13001379.8 Bug 13001379 - Datapump transport_tablespaces produces wrong dictionary metadata for some tables 

GOAL

Starting with Oracle Database 10g, you can transport tablespaces across platforms. In this note there is a step by step guide about how to do it  with ASM datafiles and with OS filesystem datafiles.
If your goal is to migrate a database to different endian platform, the following high-level steps describe how to migrate a database to a new platform using transportable tablespace:

1.- Create a new, empty database on the destination platform.
2.- Import objects required for transport operations from the source database into the destination database.
3.- Export transportable metadata for all user tablespaces from the source database.
4.- Transfer data files for user tablespaces to the destination system.
5.- Use RMAN to convert the data files to the endian format of the destination system.
6.- Import transportable metadata for all user tablespaces into the destination database.
7.- Import the remaining database objects and metadata (that were not moved by the transport operation) 
    from the source database into the destination database.        


You could also convert the datafiles at source platform and once converted transfer them to destination platform.
The MAA white paper "Platform Migration Using Transportable Tablespace" is available at
http://www.oracle.com/technetwork/database/features/availability/maa-wp-11g-platformmigrationtts-129269.pdf

From 11.2.0.4, 12C and further, if converting to Linux x86-64 consider to follow this doc:
   Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup [1389592.1]

SOLUTION

Supported platforms

You can query the V$TRANSPORTABLE_PLATFORM view to see the platforms that are supported and to determine each platform's endian format (byte ordering).
SQL> COLUMN PLATFORM_NAME FORMAT A32
SQL> SELECT * FROM V$TRANSPORTABLE_PLATFORM;

PLATFORM_ID PLATFORM_NAME                    ENDIAN_FORMAT
----------- -------------------------------- --------------
          1 Solaris[tm] OE (32-bit)          Big
          2 Solaris[tm] OE (64-bit)          Big
          7 Microsoft Windows IA (32-bit)    Little
         10 Linux IA (32-bit)                Little
          6 AIX-Based Systems (64-bit)       Big
          3 HP-UX (64-bit)                   Big
          5 HP Tru64 UNIX                    Little
          4 HP-UX IA (64-bit)                Big
         11 Linux IA (64-bit)                Little
         15 HP Open VMS                      Little
          8 Microsoft Windows IA (64-bit)    Little
          9 IBM zSeries Based Linux          Big
         13 Linux 64-bit for AMD             Little
         16 Apple Mac OS                     Big
         12 Microsoft Windows 64-bit for AMD Little
         17 Solaris Operating System (x86)   Little

If the source platform and the target platform are of different endianness, then an additional step must be done on either the source or target platform to convert the tablespace being transported to the target format. If they are of the same endianness, then no conversion is necessary and tablespaces can be transported as if they were on the same platform.

Transporting the tablespace

  1. Prepare for export of the tablespace.
    • Check that the tablespace will be self contained:
SQL> execute sys.dbms_tts.transport_set_check('TBS1,TBS2', true);
SQL> select * from sys.transport_set_violations;

Note: these violations must be resolved before the tablespaces can be transported.
    • The tablespaces need to be in READ ONLY mode in order to successfully run a transport tablespace export:
SQL> ALTER TABLESPACE TBS1 READ ONLY;
SQL> ALTER TABLESPACE TBS2 READ ONLY;
  1. Export the metadata.
    • Using the original export utility:
exp userid=\'sys/sys as sysdba\' file=tbs_exp.dmp log=tba_exp.log transport_tablespace=y tablespaces=TBS1,TBS2
    • Using Datapump export:
      First create the directory object to be used for Datapump, like in:
CREATE OR REPLACE DIRECTORY dpump_dir AS '/tmp/subdir' ;
GRANT READ,WRITE ON DIRECTORY dpump_dir TO system;

Then initiate Datapump Export:
expdp system/password DUMPFILE=expdat.dmp DIRECTORY=dpump_dir TRANSPORT_TABLESPACES = TBS1,TBS2

If you want to perform a transport tablespace operation with a strict containment check, use the TRANSPORT_FULL_CHECK parameter:
expdp system/password DUMPFILE=expdat.dmp DIRECTORY = dpump_dir TRANSPORT_TABLESPACES= TBS1,TBS2 TRANSPORT_FULL_CHECK=Y

If the tablespace set being transported is not self-contained then the export will fail.
  1. Use V$TRANSPORTABLE_PLATFORM to determine the endianness of each platform. You can execute the following query on each platform instance:
SELECT tp.platform_id,substr(d.PLATFORM_NAME,1,30), ENDIAN_FORMAT
FROM V$TRANSPORTABLE_PLATFORM tp, V$DATABASE d
WHERE tp.PLATFORM_NAME = d.PLATFORM_NAME;

If you see that the endian formats are different and then a conversion is necessary for transporting the tablespace set:
RMAN> convert tablespace TBS1 to platform="Linux IA (32-bit)" FORMAT '/tmp/%U';

RMAN> convert tablespace TBS2 to platform="Linux IA (32-bit)" FORMAT '/tmp/%U';

Then copy the datafiles as well as the export dump file to the target environment.
  1. Import the transportable tablespace.
    • Using the original import utility:
imp userid=\'sys/sys as sysdba\' file=tbs_exp.dmp log=tba_imp.log transport_tablespace=y datafiles='/tmp/....','/tmp/...'
    • Using Datapump:
CREATE OR REPLACE DIRECTORY dpump_dir AS '/tmp/subdir';
GRANT READ,WRITE ON DIRECTORY dpump_dir TO system;

Followed by:
impdp system/password DUMPFILE=expdat.dmp DIRECTORY=dpump_dir TRANSPORT_DATAFILES='/tmp/....','/tmp/...' REMAP_SCHEMA=(source:target) REMAP_SCHEMA=(source_sch2:target_schema_sch2)

You can use REMAP_SCHEMA if you want to change the ownership of the transported database objects.
  1. Put the tablespaces in read/write mode:
SQL> ALTER TABLESPACE TBS1 READ WRITE;
SQL> ALTER TABLESPACE TBS2 READ WRITE;

Using DBMS_FILE_TRANSFER

You can also use DBMS_FILE_TRANSFER to copy datafiles to another host.
From 12c and in 11.2.0.4 DBMS_FILE_TRANSFER does the conversion by default. Using DBMS_FILE_TRANSFER the destination database converts each block when it receives a file from a platform with different endianness. Datafiles can be imported after they are moved to the destination database as part of a transportable operation without RMAN conversion.
In releases lower than 11.2.0.4  you need to follow the same steps specified above for ASM files. But if the endian formats are different then you must use the RMAN convert AFTER  transfering the files. The files cannot be copied directly between two ASM instances at different platforms.

This is an example of usage:
RMAN> CONVERT DATAFILE
      '/hq/finance/work/tru/tbs_31.f',
      '/hq/finance/work/tru/tbs_32.f',
      '/hq/finance/work/tru/tbs_41.f'
      TO PLATFORM="Solaris[tm] OE (32-bit)"
      FROM PLATFORM="HP TRu64 UNIX"
      DB_FILE_NAME_CONVERT= "/hq/finance/work/tru/", "/hq/finance/dbs/tru"
      PARALLELISM=5;

The same example, but here showing the destination being an +ASM diskgroup:
RMAN> CONVERT DATAFILE
      '/hq/finance/work/tru/tbs_31.f',
      '/hq/finance/work/tru/tbs_32.f',
      '/hq/finance/work/tru/tbs_41.f'
      TO PLATFORM="Solaris[tm] OE (32-bit)"
      FROM PLATFORM="HP TRu64 UNIX"
      DB_FILE_NAME_CONVERT="/hq/finance/work/tru/", "+diskgroup"
      PARALLELISM=5;


*** WARNING ***
  • Index Organized Tables (IOT) can become corrupt when using Transportable Tablespace (TTS) from Solaris, Linux or AIX to HP/UX.
    This is a restriction caused by BUG:9816640.
    Currently there is no patch for this issue, the Index Organized Tables (IOT) need to be recreated after the TTS.

    See Document 1334152.1 Corrupt IOT when using Transportable Tablespace to HP from different OS
    .
  • When using dropped columns, Bug:13001379 - Datapump transport_tablespaces produces wrong dictionary metadata for some tables can occur.See Document 1440203.1 for details on this alert.
Known issue Using DBMS_FILE_TRANSFER

=> Unpublished Bug 13636964 - ORA-19563 from RMAN convert on datafile copy transferred with DBMS_FILE_TRANSFER (Doc ID 13636964.8)
 Versions confirmed as being affected   
    11.2.0.3 
 This issue is fixed in  
    12.1.0.1 (Base Release)
    11.2.0.4 (Future Patch Set) 
  
Description

    A file transferred using DBMS_FILE_TRANSFER fails during an RMAN convert 
    operation.
    eg:
     RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
     RMAN-00571: ===========================================================
     RMAN-03002: failure of conversion at target command at 01/24/2012 16:22:23
     ORA-19563: cross-platform datafile header validation failed for file +RECO/soets_9.tf 
   
    Rediscovery Notes:
     If RMAN convert fails on a file transferred using DBMS_FILE_TRANSFER 
     then it may be due to this bug
   
    Workaround
     Transfer the file using OS facilities.
=> Dbms_file_transfer Corrupts Dbf File When Copying between endians (Doc ID 1262965.1)

 

Additional Resources

Community: Database Utilities

Still have questions? Use the above community to search for similar discussions or start a new discussion on this subject.

Limitations on Transportable Tablespace Use

  1. The source and target database must use the same character set and national character set.
  2. You cannot transport a tablespace to a target database in which a tablespace with the same name already exists. However, you can rename either the tablespace to be transported or the destination tablespace before the transport operation.
  3. Objects with underlying objects (such as materialized views) or contained objects (such as partitioned tables) are not transportable unless all of the underlying or contained objects are in the tablespace set.
    • Review Table "Objects Exported and Imported in Each Mode" from the Oracle Database Utilities documentation, there are several object types that are not exported in tablespace mode.
  4. If the owner/s of tablespace objects does not exist on target database, the usernames need to be created manually before starting the transportable tablespace import.
    • If you use spatial indexes, then:
      • be aware that TTS across different endian platforms are not supported for spatial indexes in 10gR1 and 10gR2; such a limitation has been released in 11g
      • specific Spatial packages must be run before exporting and after transportation, please see Oracle Spatial documentation.
  5. Beginning with Oracle Database 11g Release 1, you must use only Data Pump to export and import the tablespace metadata for tablespaces that contain XMLTypes.

    The following query returns a list of tablespaces that contain XMLTypes:
select distinct p.tablespace_name
from dba_tablespaces p, dba_xml_tables x, dba_users u, all_all_tables t
where t.table_name=x.table_name and
      t.tablespace_name=p.tablespace_name and
      x.owner=u.username;

Transporting tablespaces with XMLTypes has the following limitations:
a.                   The target database must have XML DB installed.
    1. Schemas referenced by XMLType tables cannot be the XML DB standard schemas.
    2. Schemas referenced by XMLType tables cannot have cyclic dependencies.
    3. Any row level security on XMLType tables is lost upon import.
    4. If the schema for a transported XMLType table is not present in the target database, it is imported and registered. If the schema already exists in the target databasean error is returned unless the ignore=y option is set.
  1. Advanced Queues Transportable tablespaces do not support 8.0-compatible advanced queues with multiple recipients.
  2. You cannot transport the SYSTEM tablespace or objects owned by the user SYS.
  3. Opaque Types Types(such as RAW, BFILE, and the AnyTypes) can be transported, but they are not converted as part of the cross-platform transport operation. Their actual structure is known only to the application, so the application must address any endianness issues after these types are moved to the new platform.
  4. Floating-Point Numbers BINARY_FLOAT and BINARY_DOUBLE types are transportable using Data Pump but not the original export utility, EXP.
  5. Please also check Document 1454872.1 - Transportable Tablespace (TTS) Restrictions and Limitations: Details, Reference, and Version Where Applicable

Transportable tablespace EXP/IMP of ASM files

  • Using RMAN CONVERT

    There is no direct way to exp/imp ASM files as transportable tablespace. However, the funcationality can be done via RMAN.

    You must follow this steps:
    1. Prepare for exporting the tablespace.
      • Check that the tablespace will be self contained:
SQL>execute sys.dbms_tts.transport_set_check('TBS1,TBS2', true);
SQL> select * from sys.transport_set_violations;

Note: these violations must be resolved before the tablespaces can be transported.
      • The tablespaces need to be in READ ONLY mode in order to successfully run a transport tablespace export:
SQL> ALTER TABLESPACE TBS1 READ ONLY;
SQL> ALTER TABLESPACE TBS2 READ ONLY;
    1. Export the metadata.
      • Using the original export utility:
exp userid=\'sys/sys as sysdba\' file=tbs_exp.dmp log=tba_exp.log transport_tablespace=y tablespaces=TBS1,TBS2
      • Using Datapump Export:
CREATE OR REPLACE DIRECTORY dpump_dir AS '/tmp/subdir';
GRANT READ,WRITE ON DIRECTORY dpump_dir TO system;

followed by:
expdp system/password DUMPFILE=expdat.dmp DIRECTORY=dpump_dir TRANSPORT_TABLESPACES = TBS1,TBS2

If you want to perform a transport tablespace operation with a strict containment check, use the TRANSPORT_FULL_CHECK parameter:
expdp system/password DUMPFILE=expdat.dmp DIRECTORY = dpump_dir TRANSPORT_TABLESPACES= TBS1,TBS2 TRANSPORT_FULL_CHECK=Y

    1. If the tablespace set being transported is not self-contained, then the export will fail.
    2. Use V$TRANSPORTABLE_PLATFORM to find the exact platform name of target database. You can execute the following query on target platform instance:
SELECT tp.platform_id,substr(d.PLATFORM_NAME,2,30), ENDIAN_FORMAT
FROM V$TRANSPORTABLE_PLATFORM tp, V$DATABASE d
WHERE tp.PLATFORM_NAME = d.PLATFORM_NAME;
    1. Generate an OS file from the ASM file, in target platform format:
RMAN> CONVERT TABLESPACE TBS1
      TO PLATFORM 'HP-UX (64-bit)' FORMAT '/tmp/%U';
RMAN> CONVERT TABLESPACE TBS2
      TO PLATFORM 'HP-UX (64-bit)' FORMAT '/tmp/%U';
    1. Copy the generated file to target server if different from source.
    2. Import the transportable tablespace
      • Using the original import utility:
imp userid=\'sys/sys as sysdba\' file=tbs_exp.dmp log=tba_imp.log transport_tablespace=y datafiles='/tmp/....','/tmp/...'
      • Using Datapump Import:
CREATE OR REPLACE DIRECTORY dpump_dir AS '/tmp/subdir';
GRANT READ,WRITE ON DIRECTORY dpump_dir TO system;

followed by:
impdp system/password DUMPFILE=expdat.dmp DIRECTORY=dpump_dir TRANSPORT_DATAFILES='/tmp/....','/tmp/...' REMAP_SCHEMA=(source:target) REMAP_SCHEMA=(source_sch2:target_schema_sch2)

You can use REMAP_SCHEMA if you want to change the ownership of the transported database objects.
    1. Put the tablespaces in read/write mode:
SQL> ALTER TABLESPACE TBS1 READ WRITE;
SQL> ALTER TABLESPACE TBS2 READ WRITE;

If you want to transport the datafiles from ASM area to filesystem, you have finished after the above steps. But if you want to transport tablespaces between two ASM areas you must continue.
    1. Copy the datafile '/tmp/....dbf' into the ASM area using rman:
rman nocatalog target /
RMAN> backup as copy datafile '/tmp/....dbf' format '+DGROUPA';

where +DGROUPA is the name of the ASM diskgroup.
    1. Switch the datafile to the copy.
      If the 10g database is open you need to offline the datafile first:
SQL> alter database datafile '/tmp/....dbf' offline;

Switch to the copy:
rman nocatalog target /
RMAN> switch datafile '/tmp/....dbf' to copy;

Note down the name of the copy created in the +DGROUPA diskgroup, ex. '+DGROUPA/s101/datafile/tts.270.5'.
    1. Put the datafile online again, we need to recover it first:
SQL> recover datafile '+DGROUPA/s101/datafile/tts.270.5';
SQL> alter database datafile '+DGROUPA/s101/datafile/tts.270.5' online;
    1. Check if datafile is indeed part of the ASM area and online:
SQL> select name, status from v$datafile;

The output should be:
+DGROUPA/s101/datafile/tts.270.5 ONLINE
  • Using DBMS_FILE_TRANSFER

    You can also use DBMS_FILE_TRANSFER to copy datafiles from one ASM disk group to another, even on another host. Starting with 10g release 2 you can also use DBMS_FILE_TRANSFER also to copy datafiles from ASM to filesystem and to filesystem to ASM.

    The PUT_FILE procedure reads a local file or ASM and contacts a remote database to create a copy of the file in the remote file system. The file that is copied is the source file, and the new file that results from the copy is the destination file. The destination file is not closed until the procedure completes successfully.

    Syntax:
DBMS_FILE_TRANSFER.PUT_FILE(
   source_directory_object       IN  VARCHAR2,
   source_file_name              IN  VARCHAR2,
   destination_directory_object  IN  VARCHAR2,
   destination_file_name         IN  VARCHAR2,
   destination_database          IN  VARCHAR2);

Where:
    • source_directory_object: The directory object from which the file is copied at the local source site. This directory object must exist at the source site.
    • source_file_name: The name of the file that is copied from the local file system. This file must exist in the local file system in the directory associated with the source directory object.
    • destination_directory_object: The directory object into which the file is placed at the destination site. This directory object must exist in the remote file system.
    • destination_file_name: The name of the file placed in the remote file system. A file with the same name must not exist in the destination directory in the remote file system.
    • destination_database: The name of a database link to the remote database to which the file is copied.

If we want to use DBMS_FILE_TRANSFER.PUT_FILE to transfer the file from source to destination host, the steps 3,4,5 should be changed by the following:
    1. Create a directory at target database host, and give permissions to local user. This is the directory object into which the file is placed at the destination site, it must exist in the remote file system:
CREATE OR REPLACE DIRECTORY target_dir AS '+DGROUPA';
GRANT WRITE ON DIRECTORY target_dir TO "USER";
    1. Create a directory at source database host. The directory object from which the file is copied at the local source site. This directory object must exist at the source site:
CREATE OR REPLACE DIRECTORY source_dir AS '+DGROUPS/subdir';
GRANT READ,WRITE ON DIRECTORY source_dir TO "USER";
CREATE OR REPLACE DIRECTORY source_dir_1 AS '+DGROUPS/subdir/subdir_2';
    1. Create a dblink to connect to target database host:
CREATE DATABASE LINK DBS2 CONNECT TO 'user' IDENTIFIED BY 'password' USING 'target_connect';

where target_connect is the connect string for target database and USER is the user that we are going to use to transfer the datafiles.
    1. Connect to source instance. The following items are used:
      • dbs1: Connect string to source database
      • dbs2: dblink to target database
      • a1.dat: Filename at source database
      • a4.dat: Filename at target database
CONNECT user/password@dbs1

-- - put a1.dat to a4.dat (using dbs2 dblink)
-- - level 2 sub dir to parent dir
-- - user has read privs on source_dir_1 at dbs1 and write on target_dir 
-- - in dbs2
BEGIN
    DBMS_FILE_TRANSFER.PUT_FILE('source_dir_1', 'a1.dat',
                                'target_dir', 'a4.dat', 'dbs2' );
END;