Quantcast
Channel: Database Administration Tips
Viewing all 214 articles
Browse latest View live

DBA Bundle V5.7

$
0
0
The July release of DBA Bundle is now available:
https://www.dropbox.com/s/k96rl0f4g39ukih/DBA_BUNDLE5.tar?dl=0

The new features include:

- Adding Execution Plan History and enhancing the output formatting for sql_id_details.shscript for showing the details/execution plan/history of a SQL statement.
- Enhanced locating listener's log and bdump logs in oracle_cleanup.shfor cleaning DB logs.
- Enhanced the check of backup location validity in RMAN_full.shscript for taking on-demand DB backup.
- Adding multipath setting to the configuration baseline log in configuration_baseline.shscript which save the details of DBs and server configurations.
- Enhanced the 12c compatibility of dbdailychk.sh which creates health check report for the database.
- Exclude golden gate processes from the long-running queries reporting in
dbdailychk.sh and active_sessions.sh scripts.
- Added the options of modifying the backup tag, overwrite the last backup in schedule_rman_full_bkp.shwhich can be configured to perform a regular database full backup.
- Minor functionality enhancements and bug fixes in the following scripts:
export_data.sh   For exporting data.
rebuild_table.shFor rebuilding tables online.
oradebug.sh       For gathering an oradebug report.

For more reading on how to use the DBA Bundle:
http://dba-tips.blogspot.com/2014/02/oracle-database-administration-scripts.html

Ready RMAN Backup Script To Schedule from Crontab

$
0
0
This shell script can help you schedule RMAN full backup from the Crontab:
https://www.dropbox.com/home?preview=schedule_rman_full_bkp.sh

In case you are interested in an interactive script to run it manually then use this script:
https://dba-tips.blogspot.com/2017/03/rman-backup-script.html

For the first script before you schedule it to run in the crontab you have to do the following:

Modify the following mandatoryparameters at the top of the script to match your database environment details you want to back up:

ORACLE_SID=orcl              The instance name you want to back up. i.e. orcl
ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1 The Oracle Home location i.e. /u01/app/oracle/product/11.2.0/dbhome_1
BACKUPLOC=/backup        The Backup location "Full path". i.e. /backup

If you still have time you can modify the optionalparameters:

COMPRESSION=Y             In case you want to enable compression i.e. enabled
BKP_RETENTION=7          Backups older than 7 days will be deleted. [MAINTENANCEFLAG must =Yfor this parameter to take effect]
ARCH_RETENTION=7       Archivelogs older than 7 days will be deleted. [MAINTENANCEFLAG must =Yfor this parameter to take effect]
CTRL_AUTOBKP_RETENTION=7 Controlfile autobackup files older than 7 days will be deleted.  [MAINTENANCEFLAG must =Y for this parameter to take effect]
MAINTENANCEFLAG=N  If enabled it will perform the following tasks: [Default Disabled]
                                                - Enable CONTROLFILE AUTOBACKUP mode.
                                                - Enable backups to be resumed if crashed.
                                                - Maintain the good naming of the CONTROLFILE backup piece.
                                                - Crosscheck old backups.
                                                - Crosscheck Archivelog files.
                                                - Delete Expired old backups from the disk. [Based on the Backup retention you defined]
                                                - Delete Obsolete backups which are no more exist from the catalog.
                                                - Delete the old Archivelogs. [Based on the Archivelog retention you defined]
                                                - Delete the old Controlfile backups. [Based on the Controlfile retention you defined]

That's all!

This script is part of the DBA BUNDLE, to read more about it please visit this link:
http://dba-tips.blogspot.ae/2014/02/oracle-database-administration-scripts.html

DISCLAIMER: THIS SCRIPT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY. IT IS PROVIDED "AS IS".

GitHUB Version: 

Speed Up The Data Pump Import In Oracle 19c

$
0
0
Following the release of Oracle 19c --the long term supported member of the 12c family, many Oracle customers planned to migrate their older DBs especially the widely used version "11g" to the new version. Because of the restrictions on the direct upgrade from 11g to 19c, data pump method became the optimal method for this migration/upgrade.

I've run an interesting experiment on testing all the ways to speed up the data pump import on Oracle 19c. The experiment engaged lots of tuning techniques including hidden parameters as well!
 
To save the reader's time, I'll jump into the conclusion first then I'll discuss the experiment in details for those who are interested.

Conclusion:

The following steps proved to improve the data import time when using impdp:

- Disable the generation of REDO LOG data during the import by using this new impdp parameter:
TRANSFORM=DISABLE_ARCHIVE_LOGGING:Y

- Set the data pump import parallelism to 150% of the CPU core count on the machine. [This statement may not be accurate for engineered systems]
i.e. if you have 8 CPUs set the parallel parameter to 8 x 1.5 = 12
parallel=12

- Exclude statistics during the import -- to be run separately after the import, this will be faster and bug free:
EXCLUDE=STATISTICS

- Disable logical corruption checking [After the import it's recommended to run the RMAN command: VALIDATE CHECK LOGICAL DATABASE to scan the DB blocks for corruption].
alter system set DB_BLOCK_CHECKING=FALSE;
alter system set DB_BLOCK_CHECKSUM=OFF;


- Switch off the FLASHBACK mode:
alter database flashback off;

- Switch off the ARCHIVELOG mode:
-- From mount mode:
alter database noarchivelog;

-Set the DB in NO FORCE LOGGING mode:
alter database no force logging;

- Well sizing the SGA and PGA is crucial for boosting the import operation performance, as per this experiment, unless there are other DBs sharing the same server; the ideal SGA should = 50% while PGA should = 25% of the whole memory in the server.

Bonus:
 
- Disable DLM Statistics Collection which cause ora_scm* to consume high CPU & Memory: [Doc ID 2373451.1]
SQL> alter system set "_dlm_stats_collect"=0 SCOPE=SPFILE;

- Disable the hard limit of PGA which can kill sessions if it reached [known to cause node eviction in RAC]
SQL> alter system set PGA_AGGREGATE_LIMIT=0 SCOPE=BOTH;
 
- UNDO TABLESPACE and UNDO_RETENTION parameter should be big enough to support the import operation.

 
The following techniques did NOT have a significant impact on speeding up the data pump import:

- Excluding indexes from the import to create them separately after the import, this method was valid for the legacy imp where no parallelism option was available, but it's not efficient anymore with impdp. Yes it's true that impdp will create indexes with no parallelism, but will create multiple indexes at a time based on the parallelism degree. i.e. if setting parallel=8, data pump will create 8 indexes at the same time using no parallel for each index, which is faster than creating the same 8 indexes separately with 8 parallel degree for each one.

- Using manual WORK_AREA_SIZE did NOT add a significant benefit to the import performance, most probably it will slow it down.

- Unless you have a very big memory and very big /dev/shm, don't create your Temporary tablespace tempfiles under /dev/shm as most probably this will end up forcing the PGA to use the Swap space, slowing down the import process!

- As far you are disabling redo log generation by setting TRANSFORM=DISABLE_ARCHIVE_LOGGING:Y , re-creating the REDO LOG files with bigger block size i.e. 4k didn't add a significant benefit to the import process.

- Scaling up the following parameters will NOT help with speeding up the import: DB_FILE_MULTIBLOCK_READ_COUNT
_SORT_MULTIBLOCK_READ_COUNT
_DB_FILE_NONCONTIG_MBLOCK_READ_COUNT
_SMM_MAX_SIZE         ..... When setting workarea_size_policy=manual
_SMM_PX_MAX_SIZE  ..... When setting workarea_size_policy=manual


- Disabling the following parameters did NOT have a significant improvement on the import as well:
_DB_INDEX_BLOCK_CHECKING
_DB_ROW_OVERLAP_CHECKING
_DB_INDEX_BLOCK_CHECKING
_CHECK_BLOCK_AFTER_CHECKSUM


Conclusion is finished, now let's move to the experiment details:
 
Experiment Details:

The experiment ran on a machine with below specs:
OS:           OEL 7.7
CPU:        8 cores / 2.50GHz
RAM:       30 GB  
Database size:    863 GB [Tables=523 GB | Indexes=340 GB]
SGA:        15 GB
PGA:          8 GB

Before starting each import experiment, I re-create all schema users, restart the database and the OS to make sure of flushing all memory components.

For all experiments ...
 
The following impdp options/parameters were set:
Disable REDO generation: TRANSFORM=DISABLE_ARCHIVE_LOGGING:Y
Exclude importing statistics: EXCLUDE=STATISTICS
Enable timestamp for each log record: LOGTIME=ALL
 
The following DB options/parameters were set:
FORCE LOGGING is disabled:       SQL> alter database no force logging;
FLASHBACK is disabled:               SQL> alter database flashback off;
ARCHIVELOG modes is disabled: SQL> alter database noarchivelog;
Disable BLOCK CORRUPTION checking mechanism:
SQL> alter system set DB_BLOCK_CHECKING=FALSE;
SQL> alter system set DB_BLOCK_CHECKSUM=OFF;
Disable DLM Statistics Collection:
SQL> alter system set "_dlm_stats_collect"=0 SCOPE=SPFILE;
Disable the hard limit of PGA:
SQL> alter system set PGA_AGGREGATE_LIMIT=0 SCOPE=BOTH;

Running the import with different degree of parallelism based on the CPU count show this result:

 

 As shown, the best (lowest) import time achieved when used 150% or 1.5x the number of the CPUs on the machine.

It's clear that most of the import time consumed in the stage of importing indexes, and thus I tried to do further experiments with setting below hidden parameters in the hope they will improve the indexes import time without any success: [None of them show any significant impact]
alter system set "_DB_INDEX_BLOCK_CHECKING"=FALSE;
alter system set "_DB_ROW_OVERLAP_CHECKING"=FALSE;
alter system set "_DB_INDEX_BLOCK_CHECKING"=FALSE;
alter system set "_DISABLE_INDEX_BLOCK_PREFETCHING"=TRUE scope=spfile;
alter system set "_CHECK_BLOCK_AFTER_CHECKSUM"=FALSE;
alter system set "_SORT_MULTIBLOCK_READ_COUNT"=16 scope=spfile;
alter system set "_DB_FILE_NONCONTIG_MBLOCK_READ_COUNT"=22 scope=spfile;

Setting the Manual PGA has degraded the import performance!: [The limitation of 2GB is still there in 19c as well]
alter system set workarea_size_policy=manual;
alter system set "_smm_max_size"=2147483647 scope=both;
alter system set "_smm_px_max_size"=2147483647 scope=both;


Placing the TEMP tablespace temp file under /dev/shm was always ending up with swapping the memory and hence degrading the import performance.

After the import...
 
Enabled back the block checking option:
alter system set db_block_checksum=TYPICAL;
 
Executed the following RMAN script to check for corrupted blocks: [Can run in parallel with gathering statistics | 60min]
# export NLS_DATE_FORMAT='DD-Mon-YYYY HH24:MI:SS'
# vi check_physical_logical_corruption.cmd
RUN{
ALLOCATE CHANNEL c1 DEVICE TYPE DISK;
ALLOCATE CHANNEL c2 DEVICE TYPE DISK;
ALLOCATE CHANNEL c3 DEVICE TYPE DISK;
ALLOCATE CHANNEL c4 DEVICE TYPE DISK;
ALLOCATE CHANNEL c5 DEVICE TYPE DISK;
ALLOCATE CHANNEL c6 DEVICE TYPE DISK;
ALLOCATE CHANNEL c7 DEVICE TYPE DISK;
ALLOCATE CHANNEL c8 DEVICE TYPE DISK;
VALIDATE CHECK LOGICAL DATABASE;
}

# nohup rman target / cmdfile=check_physical_logical_corruption.cmd | tee check_physical_logical_corruption.log 2>&1 &

RMAN> select * from v$database_block_corruption;
no rows selected

Gather new statistics: [60 min]
SQL> EXECUTE DBMS_STATS.GATHER_DATABASE_STATS(ESTIMATE_PERCENT=>DBMS_STATS.AUTO_SAMPLE_SIZE, CASCADE => TRUE, GATHER_SYS => TRUE, degree => 8);


References:
 

Setup AWR on Standby DB

$
0
0

 Starting with Oracle 12.2, AWR can be configured and run against Standby DB, before that release (since 11gR2) the only option available for having similar data was by generating an ASH report on the Standby DB, which was limited by how much data is still available in the standby instance memory.

Here are the briefed steps of how to set up AWR on the standby DB:

[On Primary]: Unlock user sys$umf

SQL> alter user sys$umf identified by "abc#123#ORCL" account unlock;


[On Primary]: Enable "_umf_remote_enabled" parameter:

SQL> alter system set "_umf_remote_enabled"=TRUE scope=BOTH;


[On Primary]: Create two DB links, from primary to standby and vice versa:

SQL> drop database link PR_TO_STBY;
SQL> drop database link STBY_TO_PR;

SQL> create database link PR_TO_STBY CONNECT TO sys$umf IDENTIFIED BY "abc123" using 'ORCL';
SQL> create database link STBY_TO_PR CONNECT TO sys$umf IDENTIFIED BY "
abc123" using 'ORCLSTBY';


[On Primary] Add the primary DB to the new AWR Topology:

SQL> exec dbms_umf.unconfigure_node;
SQL> exec dbms_umf.configure_node ('prim');



[On Standby] Add the Standby DB to the new AWR Topology:

SQL> exec dbms_umf.UNCONFIGURE_NODE;
SQL> exec dbms_umf.configure_node ('stby', 'STBY_TO_PR');


[On Primary]: Create a new Topology:

SQL> exec DBMS_UMF.drop_topology   ('Topology_1');
SQL> exec DBMS_UMF.create_topology ('Topology_1');


[On Primary]: Register the standby database with the topology:


SQL> exec DBMS_UMF.register_node ('Topology_1', 'stby', 'PR_TO_STBY', 'STBY_TO_PR', 'FALSE', 'FALSE');

[On Primary]: Register the Standby DB as a remote DB:


SQL> exec DBMS_WORKLOAD_REPOSITORY.register_remote_database(node_name=>'stby');

If you encountered "ORA-13519": Try to unregister and register the DB again:
SQL> exec DBMS_WORKLOAD_REPOSITORY.unregister_remote_database('stby','Topology_1',TRUE);
SQL> exec DBMS_WORKLOAD_REPOSITORY.register_remote_database(node_name=>'stby');

[On Primary]: Verify the above steps by running these queries:

SQL>     set line 170
    col topology_name format a15
    col node_name       format a15
    select * from dba_umf_topology;
    select TOPOLOGY_NAME, NODE_NAME, NODE_ID, NODE_TYPE from umf$_registration;
    select * from dba_umf_registration;


[On Primary]: Create a Snapshot on the Standby DB:

SQL> alter system archive log current;
SQL> exec dbms_workload_repository.create_remote_snapshot('stby');


To generate an AWR report for the standby DB:

SQL> @?/rdbms/admin/awrrpti.sql


In case of switchover happen between primary and standby you have to do a similar role switch for AWR setup using this command:

SQL> exec DBMS_UMF.SWITCH_DESTINATION(topology_name =>'Topology_1',force_switch=> 'TRUE');


References:
https://www.oracle.com/technetwork/database/availability/redo-apply-2745943.pdf

"ORA-14451: unsupported feature with temporary table" Error When Creating a PRIVATE TEMPORARY TABLE in 19c

$
0
0

Introduction:
Private Temporary Tables (PTT) is a new feature in Oracle 18c, they have the similar characteristics of global temp tables but instead of being created under the TEMPORARY tablespace, they get created in the session's PGA, which is a great feature for boosting the performance (if your PGA is big enough to host this kind of  PTT's).

Problem:

SQL> CREATE PRIVATE TEMPORARY TABLE ORA$PTT_users ON COMMIT PRESERVE DEFINITION  AS SELECT * FROM dba_users;
CREATE PRIVATE TEMPORARY TABLE ORA$PTT_users ON COMMIT PRESERVE DEFINITION  AS SELECT * FROM dba_users
*
ERROR at line 1:
ORA-14451: unsupported feature with temporary table

SQL> sho user
USER is "SYS"

Analysis:


Above misleading error will pop-up if you create a Private Temporary Table (PTT) while connecting as SYS, SYSDBA, SYSRAC or SYSBACKUP.


Solution:


Create the PRIVATE TEMPORARY TABLE (PTT) with any other user not connecting as SYSDBA, SYSRAC, SYSBACKUP,... etc.


ORA-13831: SQL profile or patch name specified is invalid [On 19c]

$
0
0

 Problem:

As of a sudden one critical application connecting to a 19c database crashed and kept throwing the following error in its logs:

ORA-13831: SQL profile or patch name specified is invalid


Analysis:

A quick search revealed that we're hitting Bug 29942554 

Because I had to get the application up and running quickly I've decided to go with the workaround (and luckily this bug has a workaround). But why I'm writing this post then? Because the workaround is not clear, so I thought of writing this article.


Solution:

1. Searching the Failing SQL Statement details shows that a new plan was created and accepted just few seconds before the application crash, and that would be the reason for triggering this bug:

SQL> SELECT SQL_HANDLE,PLAN_NAME,CREATED,LAST_MODIFIED,FIXED,ADAPTIVE,ENABLED FROM DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE '%SELECT TYP_LF_BOOKED_HELD(FLT.FAR%' ORDER BY CREATED;



 2. Disabling that latest created SQL Plan for the problematic SQL will workaround this bug and get the application back running:


SQL> set serveroutput on
          variable a_var number;
 exec :a_var :=DBMS_SPM.ALTER_SQL_PLAN_BASELINE(
 SQL_HANDLE      => 'SQL_6ef2b0406c073b2e',
 PLAN_NAME       => 'SQL_PLAN_6xwph81q0fftfdbdc6b11',
 ATTRIBUTE_NAME  => 'enabled',
 ATTRIBUTE_VALUE => 'NO');

Conclusion:

If the failing SQL Statement is already inside a Baseline with a fixed plan but not yet enabled, this may make this SQL vulnerable to hit bug 29942554 if a new plan get accepted and added to the baseline.

As a workaround disable the new accepted plan inside the Baseline. To protect this SQL from hitting this bug again, try to enable the plan which already marked fixed in the baseline. (these are my words, not the official bug fix 😊 ).


Oracle Resource Manager | Decoding The Enegma Machine

$
0
0
Introduction:
Oracle Resource Manager (available since 8i) is one of the underestimated Oracle features, because it's not commonly used among DBAs.
In this article I'll try to explain it in a simple way to make you change your mind and start making use of it.
 
What is Resource Manager:  
In short, it gives the DBA the power of controlling system resources i.e. (CPU) by specifying who has the proirity of using system resources at the time of resource starvation. This means if you don't have CPU bottle necks throughout the day, you don't need it!

Licensing:
Resource Manager comes with Enterprise Edition without extra cost.

Why DBA should use Resource Manager:
The following scenarios illustrate the benefit of using the Resource Manager:

- You want to control the resource consumed by users using tools like SQL Developer/TOAD. (i.e. limit the CPU consumption/ Cancel the query/ Kill the session/ Limit the used degree of parallelism).
- In case there is a resource contention occur at night and you have a very important ETL that should complete on time, and you want Oracle to give this job the highest priority.
- There is an important DB service being used by finance applications at the end of the month, and you don't want other departments connecting via different services to compete the CPU resource with that finance service.
- You want the night RMAN full backup job to release the CPU resource for production applications in case a CPU contention happen at night.

How to use Resource Manager:
Configuring Resource Manager is a bit complicated, but if you follow the right sequence it will be a piece of cake.

Now it's time to setup a Plan and its Consumer Groups and Map these consumer Groups to Consumers. Before getting confused with these terms, let me first start with an example simplifies them to you:

Imagine you have opened a new fried chicken chain called Zeko Fried Chickens ZFC:
You will start with putting a business plan that will boost the food production and get the customers served as quickly as possible [let's refer to this plan as Resource Plan] the plan is as follows:
- You categorized the food production into 3 main meals [Spicy , Non-Spicy and Kids meal]. [let's refer to the meals as Consumer Groups]- You categorize your customers into three categories (Adults like spicy food, Adults don't like spicy food and kids). [Let's refer to the customers as Consumers]
- When customers come in, they will order one of the above mentioned meals, each meal will be ready within 2 minutes. [Let's refer to the process of delivering the meals to the customers as Plan Directive]

Congrats! if you understood the above example you understood the Resource Manager components;
Resource Plan specifies how much CPU will be shared with consumer groups, who will be assigned to these consumer groups, and the distribution of the rest of unused CPU if available.
Consumer Group defines how much CPU resource will be used by specific consumers.
Consumers are the ones who will utilize the resources allocated to the consumer group.
Plan Directive defines the criteria by which the Consumers will get assigned to Consumer Groups.

Now let's move to the creation of the Resource Manager components ...

- First, create something called Pending Area, it's kind of a temporary area Oracle will use to track/validate the changes you are doing to the resource manager to maintain the integrity of the Resource Manager configurations and avoid any miss up to happen. This Pending Area will be associated with your session only, at the end of setting up the Resource Manager you have to close/finish this Pending Area in order to validate and submit your changes. It's Kinda of BEGIN & END in PL/SQL but this one is specific to the Resource Manager.
 
EXEC  DBMS_RESOURCE_MANAGER.clear_pending_area();
EXEC  DBMS_RESOURCE_MANAGER.create_pending_area(); 



Create a Plan:
EXEC  DBMS_RESOURCE_MANAGER.create_plan('prod_plan', 'Plan for a combination of high and low priority tasks.');

    Rollback: Delete Plan:
    -- EXEC dbms_resource_manager.DELETE_PLAN_CASCADE ('prod_plan');

Create consumer groups:
EXEC  DBMS_RESOURCE_MANAGER.create_consumer_group('high_cg',       'high priority free to utilize the cpu');
EXEC  DBMS_RESOURCE_MANAGER.create_consumer_group('low_cg',        'low priority');
EXEC  DBMS_RESOURCE_MANAGER.create_consumer_group('conditioned_cg','low priority when met some conditions');


    Rollback: Delete Consumer Groups:
    -- EXEC DBMS_RESOURCE_MANAGER.delete_consumer_group('high_cg');
    -- EXEC DBMS_RESOURCE_MANAGER.delete_consumer_group('low_cg');
    -- EXEC DBMS_RESOURCE_MANAGER.delete_consumer_group('conditioned_cg');


-- Create the Plan Directive:
Plan Directive defines the resource limits for each Consumer group: [Here is the core idea of the Resource Manager, if you understand it, you understand the whole topic]

Note: MGMT_Px represent the CPU level, MGMT_P1 is the capacity of 100% of all CPUs (cores), whatever will remain unused (leftover) from MGMT_P1 it can be utilized by MGMT_P2 (level2), and whatever leftover from level2 can be used by MGMT_P3 and so on up to 8 levels. Which means if MGMT_P1 is utilizing 100% no CPU will remain left for MGMT_P2.




Ideally, all apps/services should have a share in level 1 (MGMT_P1) each share represent % of total CPU, all shares combined should not exceed 100%, This share doesn't restrict the App/service of using 100% of the CPU if CPU is not utilized by other services (as long as the active running sessions is less than the number of CPUs), but it will maintain that at anytime the Apps/services will get their defined % share in case there are other sessions competing for CPU resources (CPU is busy).
 
This is similar to the lion family, when they are not hungry, and meat is available, anyone of the lion family can eat peacfully from the meat (no CPU contention), but when they all become hungry and meat is not enough for all (CPU contention), here the rule will apply (Plan Directive), the lion will eat first till it get full, then the lionesses and last the lion kids.

Note: There is a consumer group exist by default called "OTHER_GROUPS", it MUST be part of any of defined plan directive.

Note: To drop a consumer group you must start with dropping the lowest MGMT_Px consumer group.
Note: Plan directive can be modified (dropped/recreated) on the fly and it will reflect immediately on the current connected sessions once the pending area get submitted.

Define a separate plan directive for default "OTHER_GROUPS": [Level 1 - highest]
BEGIN
  DBMS_RESOURCE_MANAGER.create_plan_directive (
    plan             => 'prod_plan',
    group_or_subplan => 'OTHER_GROUPS',
    comment          => 'high priority by default',
    MGMT_P1          => 80,
    MGMT_P2          => 0);
End;
/

    Rollback: Delete Plan Directive:
    -- EXEC DBMS_RESOURCE_MANAGER.DELETE_PLAN_DIRECTIVE (plan=>'prod_plan', group_or_subplan=>'OTHER_GROUPS');
 
 
Define the Conditioned group: [level 2]
BEGIN
  DBMS_RESOURCE_MANAGER.create_plan_directive(
    plan             => 'prod_plan',
    group_or_subplan => 'conditioned_cg',
    comment          => 'if the utilization met specific parameter lower the priority',
    MGMT_P1          => 0,
    MGMT_P2          => 100,
    MGMT_P3          => 0,
    -- Switch to other group (with lower CPU)/Cancel Call/Kill Session if the switch conditions are met:
--  switch_group        => 'low_cg',
    switch_group        => 'CANCEL_SQL',
--  switch_group        => 'KILL_SESSION',
    -- If Elapsed Time exceeds 120 seconds:
    switch_time          => 120,
    -- If the Number of I/O requests exceeds 5000:
    switch_io_reqs      => 5000,
    -- If the Amount of I/O requested exceeds 100M:
    switch_io_megabytes => 100,
    switch_for_call      => TRUE
    );
End;
/

    Rollback: Delete Plan Directive:
    -- EXEC DBMS_RESOURCE_MANAGER.DELETE_PLAN_DIRECTIVE (plan=>'prod_plan',group_or_subplan=>'conditioned_cg');
 
 
Define the LOW Priority group: [level 3]
BEGIN
  DBMS_RESOURCE_MANAGER.create_plan_directive (
    plan                      => 'prod_plan',
    group_or_subplan => 'low_cg',
    comment              => 'Low Priority - level 2',
    -- Limit the number of the concurrent active sessions at any given time for the sessions associated to this consumer group:
    --ACTIVE_SESS_POOL_P1 => 32
    -- Limit the degree of parallelism for the sessions associated to this consumer group:
    --PARALLEL_DEGREE_LIMIT_P1 => 2,
    MGMT_P1          => 20
   );
End;
/

    Rollback: Delete Plan Directive:
    -- EXEC DBMS_RESOURCE_MANAGER.DELETE_PLAN_DIRECTIVE (plan=>'prod_plan',group_or_subplan=>'low_cg');


Validate/Apply the resource plan:
EXEC DBMS_RESOURCE_MANAGER.validate_pending_area;
EXEC DBMS_RESOURCE_MANAGER.submit_pending_area();


Map/Assign Users/Services/Modules/Machines to Consumer Groups:

Assign the session connecting through reporting_svc service to conditioned_cg consumer group:

create a pending area: [temporary work area for Resource Management configuration until it get submitted]
EXEC  DBMS_RESOURCE_MANAGER.clear_pending_area();
EXEC  DBMS_RESOURCE_MANAGER.create_pending_area();


BEGIN
DBMS_RESOURCE_MANAGER.set_consumer_group_mapping (
  --attribute     => DBMS_RESOURCE_MANAGER.oracle_user,
  --attribute     => DBMS_RESOURCE_MANAGER.module_name,
  --attribute     => DBMS_RESOURCE_MANAGER.client_os_user,
  --attribute     => DBMS_RESOURCE_MANAGER.client_program,
  --attribute     => DBMS_RESOURCE_MANAGER.client_machine,
  --attribute     => DBMS_RESOURCE_MANAGER.service_module
,
  attribute       => DBMS_RESOURCE_MANAGER.service_name,
  value           => 'reporting_svc',
  consumer_group  => 'conditioned_cg');
END;
/

Here we are providing service_name but I'm showing you the other available attributes (as hashed) to show you the other attibutes you can use to map sessions to consumer group.
 
    e.g. To map all the connections from SQL Developer to Conditioned group:
           BEGIN
           DBMS_RESOURCE_MANAGER.set_consumer_group_mapping (
           attribute     => DBMS_RESOURCE_MANAGER.module_name,
          
value          => 'SQL Developer',
           consumer_group  => 'conditioned_cg');
           END;
           /


Now all the sessions that connect to service "reporting_svc" are mapped to "conditioned_cg" onsumer grroup.

    Rollback: To Remove an attribute, run the same command with the same attribute & value, but remove "consumer_group" parameter:
    BEGIN
    DBMS_RESOURCE_MANAGER.set_consumer_group_mapping (
      attribute       => DBMS_RESOURCE_MANAGER.service_name,
      value           => 'reporting_svc');
    END;
    /

Validate/Apply the resource plan:
EXEC DBMS_RESOURCE_MANAGER.validate_pending_area;
EXEC DBMS_RESOURCE_MANAGER.submit_pending_area();


Grant permission to All users to use/switch to the created Consumer Groups:

EXEC dbms_resource_manager_privs.grant_switch_consumer_group('public', 'high_cg', FALSE);
EXEC dbms_resource_manager_privs.grant_switch_consumer_group('public', 'low_cg',  FALSE);
EXEC dbms_resource_manager_privs.grant_switch_consumer_group('public', 'conditioned_cg', FALSE);


Activiate the Resource Plan:
SQL> ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = prod_plan SCOPE=BOTH SID='*';
Or:
SQL> EXEC DBMS_RESOURCE_MANAGER.SWITCH_PLAN ('prod_plan');
 
   Rollback: Reset the plan for RAC:
   --ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = DEFAULT_PLAN;
  Rollback: Reset the plan Standalone:
   --ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = '';

Note: Scheduled maintenance windows which run auto tasks such as Gather Statistics will ativiate their own Resource Plan when they run,
you can completly disable this behaviour by setting static parameter "_resource_manager_always_off"=TRUE.

To prevent a resource plan from being changed during such maintenance windows use FORCE keyword:
SQL> ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'FORCE:prod_plan' SCOPE=BOTH SID='*';

The advantage of keeping default resource plan DEFAULT_PLAN on RAC protects PMON and LMS, from CPU starvation, SYS & SYSTEM sessions have the highest priority, maintenance AUTO TASKS have the lowest priority.

 
Monitoring Resource Manager:
 
Check which Resource Plan is currently Active: [CPU should be ON]
SQL> select name, cpu_managed from v$rsrc_plan where is_top_plan = 'TRUE';  

Check a Consumer Plan and its consumer Groups:
SQL> select group_or_subplan from dba_rsrc_plan_directives where plan = 'prod_plan';

Check the History of activated Resource Plans:
SQL> select name, to_char(start_time, 'MON DD HH24:MI') start_time, to_char(end_time, 'MON DD HH24:MI') end_time from v$rsrc_plan_history order by start_time;

Check the Consumer Groups Mapping Attributes:
SQL> select * from DBA_RSRC_GROUP_MAPPINGS order by consumer_group;
 
Check the mapped Consumer Group to the connected sessions:
SQL> SELECT username,initial_rsrc_consumer_group FROM dba_users;
 
SQL> select name,active_sessions,io_service_time,small_read_megabytes from V$RSRC_CONSUMER_GROUP;
 
SQL> SELECT username,module,sid,serial#,resource_consumer_group,count(*) from v$session
     where username is not null group by username,module,sid,serial#,resource_consumer_group order by 2,1;
 
SQL> SELECT username,sid, resource_consumer_group FROM  v$session WHERE  SERVICE_NAME='reporting_svc';

     -- Display the Sessions and their current consumer group:
     col ORIGINAL_CONSUMER_GROUP for a30
     select s.username,r.sid, r.mapped_consumer_group, r.mapping_attribute,  c.consumer_group original_consumer_group
     from v$rsrc_session_info r, dba_rsrc_consumer_groups c, v$session s where r.orig_consumer_group_id = c.consumer_group_id and s.sid=r.sid;


     -- Display the Sessions that moved between consumer groups:
     select r.sid, c1.consumer_group original_consumer_group, c2.consumer_group current_consumer_group
     from v$rsrc_session_info r, dba_rsrc_consumer_groups c1, dba_rsrc_consumer_groups c2  where r.orig_consumer_group_id = c1.consumer_group_id
     and r.current_consumer_group_id = c2.consumer_group_id and r.orig_consumer_group_id != r.current_consumer_group_id;


Check Consumer Groups:
col CONSUMER_GROUP     for a30
col CATEGORY        for a20
col COMMENTS        for a30
col CPU_METHOD        for a20
col MGMT_METHOD        for a20
col status        for a10
col MANDATORY        for a10
select CONSUMER_GROUP,status,mandatory,CPU_METHOD,MGMT_METHOD,CATEGORY,substr(COMMENTS,1,30) "COMMENTS" from DBA_RSRC_CONSUMER_GROUPS
where  consumer_group not like '%ORA$%'
and    CATEGORY='OTHER';


Check the Consumer Group attributes:
SQL> select ATTRIBUTE,value,status from DBA_RSRC_GROUP_MAPPINGS where CONSUMER_GROUP='CONDITIONED_CG';

Consumer Groups CPU Consumption:
SQL> select to_char(begin_time, 'HH:MI') time, consumer_group_name,   60 * (select value from v$osstat where stat_name = 'NUM_CPUS') total_CPU,   60 * (select value from v$parameter where name = 'cpu_count') db_total, cpu_consumed_time / 1000 consumed, cpu_consumed_time / (select value from v$parameter where name =       'cpu_count') / 600 %cpu_utilization, cpu_wait_time / 1000 throttled from v$rsrcmgrmetric_history  order by begin_time;

Note: The existance of wait event "resmgr:cpu quantum" represent the CPU throttling that caused by the Resource Manager when DB has workload exceeds the CPU capacity.

References:
https://www.oracle.com/technetwork/database/performance/resource-manager-twp-133705.pdf
https://www.oracle.com/technetwork/articles/servers-storage-admin/o11-056-oracledb-rm-419380.pdf
https://oracle-base.com/articles/8i/resource-manager-8i
http://www.dba-oracle.com/t_consumer_groups.htm

Major Update to Rebuild Table Script

$
0
0

 Few months back:

I've shared a script to rebuild tables in Oracle using online rebuild options like [(DBMS_REDEFINITION (9i+) & ALTER TABLE MOVE ONLINE (12.2+)] if those features are not available in the database (i.e. database edition is Standard Edition) the script will utilize the legacy "ALTER TABLE MOVE" command along with rebuilding indexes.

The original post link: http://dba-tips.blogspot.com/2019/05/rebuild-table-script-and-reclaim-wasted.html

What is new?

I received many enhancements requests from readers along with bug fixing and here is a summary of new features:

Major Enhancements:

- When using ALTER TABLE MOVE ONLINE or the legacy one, you will be prompted to choose whether to keep the table in its original tablespace or you want to move the table to another tablespace:


Leaving it blank will rebuild the table on its original tablespace.

Of course, if you choose a different tablespace the script will automatically calculate the free space on the tablespace and make sure it's sufficient to host the table after the rebuild.

Note: This feature is not added to DBMS_REDEFINITION, although it's available starting with 12.2,  it will need the user to specify the tablespace for each index separately, I thought it will be better to not add this feature to not confuse the user, anyways the user can still use "ALTER TABLE MOVE ONLINE" option which is already available on 12.2 which will give similar result.

- Bug fixes along with reorganizing the steps to make it more simple for the user.

Minor Enhancements:

- User can enter blank value when asked for Parallelism Degree to utilize the maximum CPU power on server without the need to calculate it. "For those who are lazy to check CPU count on the machine 😊"

- Entering 0 value to Parallelism Degree will be accepted to disable the parallelism.


By the way, the info statement shown above "don't exceed the current number of CPUs" is my advice, of course you can exceed the number of CPUs and it may be faster for you, but in most cases I studied it won't help much, better you validate that yourself on your hardware!

- More notifications, messages added to the script to keep the user updated with what is going on.

- Added more tolerance for user's wrong inputs. 

- If the table selected for rebuild is being replicated by goldengate or streams, the user will get an info message that target table may miss some data during the table rebuild (this took me days of testing ad building case scenarios till I figured out this limitation!). By the way, this is not a script limitation, it's how the Oracle rebuild technology works internally so far.

- changed the color of important messages from green to yellow to give it more appearance.

 

To download the script:

https://www.dropbox.com/s/bmgbc0u76okokcs/rebuild_table.sh?dl=0


GitHub version is updated as well


DBA BUNDLE 5.8

$
0
0

September's release of the DBA Bundle is now available: (It's a combination of Aug+Sep releases)

dbdailychk.sh[For generating a database Health Check Report]:
- Added Memory utilization check feature, combining both RAM and SWAP in the calculation:
The following parameters need to be edited by the user to match the environment requirements:
 CHECK_MEMORY=Y          # REPORT LOW MEMORY USING BELOW TWO DEFINED THRESHOLDS COMBINED [OS]
 USEDPHYSICALMEM_PCT=95 # THRESHOLD FOR RAM %UTILIZATION                                [OS]
 USEDSWAPMEM_PCT=75     # THRESHOLD FOR SWAP SPACE %UTILIZATION                         [OS]

How it works?
 
Low memory will get reported if both; RAM %USED is >=95% and SWAP space %USED is >=75% 
 
Above thresholds are generic; feel free to change them as per your experience with your systems.
e.g. if you feel your system start to get slow when the RAM %USED reach 85% and SWAP space utilization hit 10%, then you edit those parameters like this:
USEDPHYSICALMEM_PCT=85
USEDSWAPMEM_PCT=10
 
If you are not interested in getting notified about Memory high utilization, just disable this function by setting:
CHECK_MEMORY=N
 
- Reorganized the script's sections to make it easier for the user to edit and understand.
 
rebuild_table.sh [For rebuilding a table online]:
- Added the feature of rebuilding the table on a different tablespace.
- Enhanced the formatting of the outputs and the logfile.
For a detailed discussion on this script new features please visit: http://dba-tips.blogspot.com/2020/09/major-update-to-rebuild-table-script.html 
 
parameter_val.sh [For viewing Normal & Hidden Parameters]
- User can view all NON-DEFAULT parameters.
- The user can list all the parameters on the instance.
 
user_ddl.sh[For generating User creation DDL statement]
- If the database version is 12c+ the script will automatically use dbms_metadata.get_ddl to generate the DDL (User creation + Privileges + showing quotas on tablespaces).

 
- Minor functionality enhancements and bug fixes included in these scripts:
 
export_data.sh   [For exporting data]
- Fixed a directory creation bug.
 
dbalarm.sh[For database monitoring]
- Excluded the reporting of ORA-235 which triggers during the unlocking of the control file" as advised by MOS 2312580.1
 
rebuild_table.sh  [For rebuilding a table online]:
- Correction of DBA_REDEFINITION_ERRORS query. 
 
object_size.sh [For calculating the total object size]
- Enhanced the formatting of the outputs. 
 
aliases_DBA_BUNDLE.sh [The main Bundle deployment script]
- Removed the constraint of extracting the bundle under User's home directory, now the user is free to extract the bundle anywhere.

 
If you are new to the DBA Bundle, please visit below link to understand its functions:
http://dba-tips.blogspot.com/2014/02/oracle-database-administration-scripts.html

Script to Monitor and Report Audit Trail Records in sys.aud$

$
0
0



 

Script Description:

This script monitors the major audit trail records and failed login attempts, it can be easily deployed and customized. So far, it has been tested on Linux Environment.

Script Category: Auditing & Security

How it works:

You have to schedule this script to run in the OS scheduler "crontab", you can decide how fast you should receive a notification whenever a new "major" audit event get created. Then set the same schedule interval in minutes inside the script to determine the window of time which the script will fetch the data from sys.aud$.

e.g. If you schedule the script to run every 30 minutes in the crontab, you should set the Threshold "MINUTES" inside the scripts to 30.

The script uses sendmail as the only notification method, so you have to set the following parameter replacing the pattern youremail@yourcompany.com to your actual Email:

EMAIL="youremail@yourcompany.com"

In addition, the script has many parameters to help you narrow down the scope of audit actions monitoring, you can change the values in green color:

 HTMLENABLE=Y      # Enable HTML Email Format [Default Enabled].
 RECORDSNUM=1     # Send an Email if the sum of audit records >= the threshold [Default 1 record].
 REPORT_FAILED_LOGINS=Y    # Enable the reporting of failed login attempts. [Default Enabled].
 REPORT_AUDIT_RECORDS=Y  # Enable the reporting of audit records [Default Enabled].
 EXCLUDE_DBUSERS="'dba_bundleexp7'"      # Exclude DB user from reporting their activities [In lowercase]. e.g. EXCLUDE_DBUSERS="'sys','scott'"
 EXCLUDE_OSUSERS="'user1'"               # Exclude OS user from reporting their activities [In lowercase]. e.g. EXCLUDE_OSUSERS="'oracle','grid'"
 EXCLUDE_ACTIONS="'SELECT','SET ROLE','LOGON','LOGOFF','LOGOFF BY CLEANUP','EXPLAIN','PL/SQL EXECUTE','SYSTEM AUDIT'" # Exclude specific AUDIT EVENTS from reporting.

EXCLUDE_ACTIONS is an important parameter to help you exclude specific audit actions from getting reported. This reporting mechanism should cover only crucial activities that need immediate attention like DROP, TRUNCATE, ALTER, ... etc for example; minor activities like Log In, Log Off and SELECT shouldn't be in the scope of such monitoring mechanism; otherwise you will get your mailbox filled unnecessarily.

I've already excluded common audit actions from the scope of getting reported like:

SELECT, SET ROLE, LOGON, LOGOFF, LOGOFF BY CLEANUP, EXPLAIN, PL/SQL EXECUTE, SYSTEM AUDIT

Let's suppose you want to exclude DML's from getting reported; modify the parameter as follows:

EXCLUDE_ACTIONS="'SELECT','SET ROLE','LOGON','LOGOFF','LOGOFF BY CLEANUP','EXPLAIN','PL/SQL EXECUTE','SYSTEM AUDIT','INSERT','UPDATE','DELETE','SESSION REC'"

Ensure that you enclose each audit action between "single quotation"'' and separating between them using "comma",

To display all the available actions names that you can use for that parameter, run this statement:

SQL> select distinct action_name from dba_audit_trail order by 1;  

Feel free to add more actions to be excluded to EXCLUDE_ACTIONS parameter, and I encourage you to do so.

Precautions:

The last and the most important remaining point here is indexing sys.aud$ table:

Your audit trail table sys.aud$ may have millions/billions of rows, querying this table frequently can degrade your database performance and most probably it can bring the server on its knees; especially if it has humble resources!

If reporting audit records is important for you, then you must create the following index before start using this script and to avoid any performance degradation it can cause by this script: (Create it with online option to avoid getting the DB hung)

SQL> CREATE INDEX sys.idx_ntimestamp# ON sys.aud$(ntimestamp#) ONLINE;
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS (ownname => 'SYS', tabname => 'AUD$', cascade => TRUE, estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);

When the script run, it will check if sys.aud$ (ntimestamp#) is indexed, if it's not; it will display a warning message along with the recommended index creation statement to execute.

It is worth to mention that Oracle doesn't recommend creating any indexes on sys.aud$ table as it may degrade the performance of record insertions to sys.aud$, in addition to other minor reasons mentioned in this Note: The Effect Of Creating Index On Table Sys.Aud$ (Doc ID 1329731.1)

From my experience; I use this script along with the creation of the above index on very busy OLTP databases without noticing any performance degradation. Creating an index on sys.aud$ table is like creating an index on any other "busy table"; Yes it will add extra overhead during DML operations to maintain the index, but still Oracle can handle it efficiently.

Indeed, you are the right one to decide whether adding an index to sys.aud$ table will degrade the performance or not; based on the daily volume of audit data that get inserted to sys.aud$, along with the hardware resources of your DB server.

One last thing, you may ask why I coded the script to select directly from sys.aud$ instead of using DBA_AUDIT_TRAIL; the answer is that I've noticed in many cases that selecting from DBA_AUDIT_TRAIL will force the optimizer to not use the above mentioned indexes leading to an expensive full table scans, this is why I avoided using it.

Please feel free to share your thoughts and suggestions.

To download the script:

https://www.dropbox.com/s/vja3hptpzy7a3in/monitor_audit_records.sh?dl=0

After you click on that link, click on the down arrow at the top-right side of the page:



GitHub Version:


CRS-2974: unable to act on resource

$
0
0

Problem:


On a 19c RAC DB when shutting down any instance gracefully using srvctl command it throws this error:

$ srvctl stop instance -d proto -i proto2
PRCD-1131 : Failed to stop database proto and its services on nodes r6ttnode2
PRCR-1133 : Failed to stop database proto and its running services
PRCR-1132 : Failed to stop resources using a filter
CRS-2974: unable to act on resource 'ora.proto.db' on server 'r6ttnode2' because that would require stopping or relocating resource 'ora.proto.jdbcapp.svc' but the appropriate force flag was not specified


Analysis:


If you have created a service on RAC 19c with -preferred option, SRVCTL command will not shutdown the instance unless you use -force parameter, which will not allow the transactions to failover to the other available node in case you are using TAF policy (Transparent Application Failover).


Workarounds:


- [Recommended] First stop the services on the instance you want to shut down, then shutdown the instance gracefully using SRVCTL command: [This will allow the QUERIES to failover to the other available node]


$ srvctl stop service  -d proto -i proto2
$ srvctl stop instance -d proto -i proto2

- [Less recommended] Shutdown the instance gracefully from the SQLPLUS console: [This will allow the QUERIES to failover to the available node]


$ export ORACLE_SID=proto2
SQL> SHUTDOWN IMMEDIATE;

Note: Unless you are having and ADG or GoldenGate setup, SHUTDOWN ABORT of a RAC instance is considered a safe procedure as well. I personally start with SHUTDOWN IMMEDIATE as I've faced rare cases in the past; where ABORTING an instance can corrupt any controlfiles.

- [Least recommended] Shutdown the instance forcefully using SRVCTL command: [Current Running QUERIES will fail]


$ srvctl stop instance -d proto -i proto2 -force

Note:
This SRVCTL error doesn't show up when stopping the whole DB (all instances at once): using: $ srvctl stop database -d proto

AWR New Feature In 19c in Comparison With 11g

$
0
0

 In19c AWR report there are many new tables appear in each section of the AWR report comparing to11g's AWR. In 19c, reports and information like ASH , ADDM reports and goldengate statistics are now impeded inside the AWR where you don't have to gather them separately.

Starting with "Report Summary" sections:

- Top ADDM Findings: 

- TOP 10Foreground Wait Events: (Instead of TOP 5 in 11g)

- Wait classes: (new table)

 

- IO Profile (new table)

 

- Recovery Progress: [In case the report is taken from a Standby DB]

- In-Memory Area new item (Cache Size)


Moving to "Main Report" section:

Drilling down to each of these brand-new sections:

Goldengate related statistics are now available in the AWR: 


AQ's stats are new in AWR as well:

And here is the nice part, in 19c the ASH report is now embedded inside the AWR report, whereas you don't have to generate ASH reports separately anymore

Same like ASH, ADDM report is also available:

There are still few minor new statistics in 19c's AWR I didn't yet mention, I thought to highlight only the major sections the DBAs are interested in.



Unable to obtain current patch information due to error: 20013 When Starting up a DB Instance

$
0
0

Error:

When Starting a RAC DB instance I noticed the following error in the alertlog which was hampering the display of installed patches list:

QPI: opatch executable does not exist, opatch
QPI: OPATCH_INST_DIR not present:/u01/oracle/12.2.0.3/db/OPatch
Unable to obtain current patch information due to error: 20013, ORA-20013: DBMS_QOPATCH ran mostly in non install area
ORA-06512: at "SYS.DBMS_QOPATCH", line 2327
ORA-06512: at "SYS.DBMS_QOPATCH", line 854
ORA-06512: at "SYS.DBMS_QOPATCH", line 634
ORA-06512: at "SYS.DBMS_QOPATCH", line 2309



Analysis:

The top of the error message is clearly saying:

OPATCH_INST_DIR not present:/u01/oracle/12.2.0.3/db/OPatch

The right location of OPatch in my environment is /u01/oracle/12.2.0.3/OPatch, not as mentioned in the error message: /u01/oracle/12.2.0.3/db/OPatch

Checking the OPATCH directory location in DBA_DIRECTORIES:

SQL> set lines 170
           col DIRECTORY_NAME for a30
           col DIRECTORY_PATH for a100
           select DIRECTORY_NAME,DIRECTORY_PATH from DBA_DIRECTORIES where DIRECTORY_NAME like 'OPATCH%';


It's not only OPATCH_INST_DIR which pointing to the wrong directory, but the other OPATCH directories as well like; OPATCH_SCRIPT_DIR and OPATCH_LOG_DIR.


Solution:

As per note 2033620.1, the right OPATCH directories path should be as the following:


OPATCH_INST_DIR:       $ORACLE_HOME/OPatch     
OPATCH_SCRIPT_DIR:  $ORACLE_HOME/QOpatch
OPATCH_LOG_DIR:       $ORACLE_HOME/QOpatch

So let's correct those paths using the following commands:

SQL> CREATE OR REPLACE DIRECTORY OPATCH_INST_DIR   AS '/u01/oracle/12.2.0.3/OPatch';
SQL> CREATE OR REPLACE DIRECTORY OPATCH_SCRIPT_DIR AS '/u01/oracle/12.2.0.3/QOpatch';
SQL> CREATE OR REPLACE DIRECTORY OPATCH_LOG_DIR    AS '/u01/oracle/12.2.0.3/QOpatch';

SQL> select DIRECTORY_NAME,DIRECTORY_PATH from DBA_DIRECTORIES where DIRECTORY_NAME like 'OPATCH%';

To verify that everything is OK after correcting the directory location:

Run the following command, where it should run successfully without returning any errors:

# $ORACLE_HOME/OPatch/datapatch  -prereq



References:
Datapatch fails with "ORA-20009:"“ORA-20013: DBMS_QOPATCH ran mostly in non install area” ORACLE_HOME is a SYMBOLIC LINK Doc ID 2033620.1




SQL Tuning Script

$
0
0

 This shell script will help you tune a SQL Statement in Oracle by doing the following functions:

It will ask you for the SQL Statement sqlid, then it will do the following:

1- Display the SQL Statement Statistics like: Executions, ELAPSED/CPU time, Waits, I/O stats:

 


2- Display the SQL TEXT along with populating the bind variables:

 

 

3- Display the current Execution Plan:


4- Display the history of Execution Plans and execution statistics [if found]. [This section quoted from Tim Gorman'ssqlhistory.sql script after taking his permission (many thanks to Tim)]

This will help the user investigate the statement performance over the time by checking the change to the execution plan.


5- Display the SQL Plan Baseline, if the statement is already using a baseline for execution plan stability. [SQL Plan Baseline is an 11g new feature maintains the execution plan stability by storing the execution plans for a statement and use the best plan out of them in case the user didn't fix a plan yet]

6- If the statement is not part of SQL Plan Baseline, the script will offer the option of fixing an execution plan by creating a new baseline for this statement: [If the DB version is 11g+]

 


 7- If the statement is already in a SQL Plan Baseline, it will check the number of the available plans for this statement, if the plans are more than 1 plan, the script will display all the plans details, and will offer the option to fix a plan:

 

 You can view the plan details in a tabular format using the shown Select statement: [in 12c+]

select * from table(dbms_xplan.display_sql_plan_baseline('&sql_handle','&plan_name','typical'));

 

 Then you can get back to the script and decide which plan to FIX for this statement:


Then it will show the statement to use in case you want to rollback the change by dropping the Baseline (yes we can disable the baseline but disabling the baseline will not eliminate the optimizer of using it, disabling the baseline cannot be considered as a complete rollback here).

8- Finally the script will display the option of tuning the SQL Statement by submitting a tuning task using SQL Tuning Advisor feature [This feature is a licensed feature, please don't use it unless your company is already acquired the Diagnostic & Tuning License to avoid licensing audit troubles in the future]:

This script is provided "AS IS" without any warranty. This script is tested on Linux environments but you have to test it first on a test environment before start to use it on production.

 Special thanks to Farrukh Salman (Karkoor) for his contribution in this script.

You can Download the script from this link:

https://www.dropbox.com/s/fll8e7ybrjgsexo/sql_tune.sh?dl=0


GitHub version:



Unable to obtain current patch information due to error: 16000

$
0
0

Error:

When starting up a standby database in open mode I noticed the following error in the alertlog:

Unable to obtain current patch information as the database or pluggable database was opened for read-only access.
===========================================================
Dumping current patch information
===========================================================
Unable to obtain current patch information due to error: 16000
===========================================================



Analysis:

SQL> select dbms_sqlpatch.verify_queryable_inventory from dual;

 

Fix:

Unfortunately there is no fix for the time being as of now, but the following bug is already being worked by the development team:


Bug 21098077 - PACKAGES USED TO OBTAIN DATABASE PATCH INFORMATION SHOULD HANDLE READ-ONLY DB

Meanwhile, This error is minor and doesn't indicate any problem with the database, so it can be safely ignored.


DBA Bundle 6.0

$
0
0

 The 6th version of DBA Bundle is now available:

https://www.dropbox.com/s/llj0n4qr4puyinp/DBA_BUNDLE6.tar?dl=0

After opening the link click on the Down Arrow on the right side:




The new features include:

sql_tune.sql script can display the SQL PLAN BASELINE Details for SQL statement. It allows the user to fix an EXECUTION PLAN by creating a new BASELINE. Also enables the user to fix an EXECUTION PLAN inside an already exist BASELINE.

monitor_audit_records.sh script can report audit records on SYS.AUD$ table including failed login attempts and DMLs/DDLs. The user can control the activities that can be reported. It will recommend the user to create an index on sys.idx_ntimestamp# in order to boost the execution time of the script.

db_locks.sh script can show the locks in the database in a user-friendly output.

unlock_user.sh script can reset a user's password using enhanced password algorithm.

Minor updates and bug fixes added to the following scripts:

dbdailychk.sh... Generates daily health check report for databases

aliases_DBA_BUNDLE.sh ... Setup aliases for the bundle's scripts in the environment

export_data.sh ... export data

oradebug.sh ... generate an Oradebug report

parameter_val.sh... show the value of a visible/hidden parameter or for all non-default parameters.

 

In case you are new to the DBA Bundle, please visit below link to understand its functions and how it works:
http://dba-tips.blogspot.com/2014/02/oracle-database-administration-scripts.html

The Pursuit of Ultimate Performance On Non Production Oracle Databases

$
0
0


 The scope of this article is to disable some features --mainly related to recoverability and logging, in order to speed up Test databases that are being used to test an application functionality or a database feature. What we are doing here is similar to what mechanics do to regular cars when they convert it to a race car; they simply start this conversion by getting rid of luxuries car parts and electronics like passenger seats, AC, anti theft devices to reduce the car wight and thus make it faster.

Warning: You should NOT implement the following tips on production databases at any cost, as this will stop the database recoverability features which may lead to data loss in case of system crash or will disable logging mechanisms which can undermine problems troubleshooting!

Disable Flashback: [Flashback log generation is accounted for 2% to 10% of the overhead on the DB]

SQL> ALTER DATABASE FLASHBACK OFF;

Disable Archivelog mode: [Disabling archivelog mode can boost the overall DB performance significantly]

SQL> shutdown immediate

SQL> startup mount
SQL> alter database noarchivelog;

SQL> alter database open;

Disable Force Logging:[Force logging can put a huge load on Redo Log files even if the database in NOARCHIVELOG mode:

SQL> ALTER DATABASE no force logging;

Disable auditing:
SQL> ALTER SYSTEM SET audit_trail='NONE' scope=spfile;


Disable Recycle bin:[Objects will be permanently dropped even when you don't specify PURGE keyword]
SQL> ALTER SYSTEM SET recyclebin=off deferred;

 

Disable block corruption checking mechanism:

Block checking for detecting block corruption can add extra I/O to each write activity on DB blocks.
SQL> ALTER SYSTEM SET DB_BLOCK_CHECKING=FALSE;
SQL> ALTER SYSTEM SET db_block_checksum=OFF;
SQL> ALTER SYSTEM SET "_dlm_stats_collect"=0 SCOPE=SPFILE;


Disable Automatic Shared Memory Management (ASMM): [Applicable to production as well 👍]

If you know the optimal size for each memory component, then it's better to set them manually rather than having ASMM to do it for you, trust me; even if don't figure out the optimal size for memory pools you still can adjust them better than ASMM.

Set the following parameter to the optimal size (as possible): 

SQL> ALTER SYSTEM SET shared_pool_size=nnnn         scope=both;
SQL> ALTER SYSTEM SET "_shared_pool_reserved_pct"=10 scope=spfile;
SQL> ALTER SYSTEM SET large_pool_size=nnnn          scope=both;
SQL> ALTER SYSTEM SET java_pool_size=nnnn           scope=both;
SQL> ALTER SYSTEM SET db_cache_size=nnnn            scope=both;
SQL> ALTER SYSTEM SET streams_pool_size=nnnn     scope=both;

Then disable ASMM:

SQL> ALTER SYSTEM SET sga_target=0 scope=both;

 
Disable STATISTICS LEVEL:


SQL> ALTER SYSTEM SET STATISTICS_LEVEL=BASIC;

Disabling statistics level is very powerful as it will disable the following feature as well:
Automatic Workload Repository (AWR) Snapshots
Automatic Database Diagnostic Monitor (ADDM)
All server-generated alerts
Automatic SGA Memory Management
Automatic optimizer statistics collection
Object level statistics
End to End Application Tracing (V$CLIENT_STATS)
Database time distribution statistics (V$SESS_TIME_MODEL and V$SYS_TIME_MODEL)
Service level statistics
Buffer cache advisory
MTTR advisory
Shared pool sizing advisory
Segment level statistics
PGA Target advisory
Timed statistics
Monitoring of statistics

Disable DLM Statistics Collection: [Applicable to production as well 👍]

It's known to cause ora_scm* process to consume high CPU & Memory: [Doc ID 2373451.1]
SQL> ALTER SYSTEM SET "_dlm_stats_collect"=0 SCOPE=SPFILE;

Maintain only 1 big Redo Log member in each Redo Log group:
Having only one member inside each group reduces the I/Os on the disk, in addition, increasing the size of the REDO LOG file will reduce the frequent Redo Log switches.

Example:

SQL> ALTER DATABASE add logfile group 4 '/oradata/ORCL/redo4.log' size 10g;
SQL> ALTER DATABASE add logfile group 5 '/oradata/ORCL/redo5.log' size 10g;
SQL> ALTER DATABASE add logfile group 6 '/oradata/ORCL/redo6.log' size 10g;

SQL> ALTER DATABASE drop logfile group 1;
SQL> ALTER DATABASE drop logfile group 2;
SQL> ALTER DATABASE drop logfile group 3;


Increase log_buffer parameter: [Applicable to production as well 👍]

SQL> ALTER SYSTEM SET log_buffer=52428800 scope=spfile;


Increase fast_start_mttr_target:
Although increasing fast_start_mttr_target will increase the crash recovery time when the instance crash, but it can boost the database write activities as it doesn't need to be flushed from Redo Logs to the datafiles immediately.

Example: setting fast_start_mttr_target to 5 minutes:

SQL> ALTER SYSTEM SET FAST_START_MTTR_TARGET=300;


Use BIGFILE tablespace instead of default small file:
The performance advantage of Bigfile tablespace over the default small file tablespace is that it decrease the reserved memory inside SGA for managing the datafiles, along with decreasing the I/Os and space inside the controfile, if the machine that hosts your test database has humble resources this can help.

SQL > CREATE BIGFILE TABLESPACE bigtbs DATAFILE '/oradata/ORCL/App_data.dbf' SIZE 500g;

 

Set datafiles to AUTOEXTEND OFF: [Applicable to production as well 👍]

Make sure that datafiles have sufficient free space to accommodate new data before setting them to AUTOEXTEND OFF.

Example:

SQL>ALTER DATABASE datafile '/oradata/ORCL/users01.dbf' autoextend off ;


Use only one controlfile:

Avoid multiplexing the controlfile as this will add more I/O overhead to the hosting disk.

Example:

SQL> ALTER SYSTEM SET control_files='/oradata/ORCL/control1.ctl' scope=spfile;


Reduce the UNDO RETENTION to the minimum required to support DML operations:

SQL> ALTER SYSTEM SET undo_retention=nnn scope=both;


Disable trace_enabled parameter:

This will stop tracing system problems which is required by Oracle support for debugging.

SQL> ALTER SYSTEM SET trace_enabled=FALSE SCOPE=BOTH;


Turn OFF Listener's logging:

This supposes to stop writing log entries to the listener's logfile to reduce the I/O overhead on the underlying filesystem:
Immediate stop of listener log: [doesn't require to restart the listener but will not be considered if the 

listener restart]
# lsnrctl set log_status off

Turn OFF Listener's logging: [permanent, requires a listener restart]
# vi listener.ora

logging_listener = off

# lsnrctl listener stop
# lsnrctl listener start

 

Turn OFF SQLNET logging:
This supposes to stop writing log entries to the sqlnet's logfile to reduce the I/O overhead on the underlying filesystem:
# vi sqlnet.ora

LOG_DIRECTORY_CLIENT = /dev/null
LOG_FILE_CLIENT = /dev/null



Stop TFA:

TFA logs all Oracle RAC and OS activities and performance data, it's mainly getting used by Oracle support to help them understand the status of the RAC node at a specific period of time.

You can stop TFA by executing this command as root user:
# /etc/init.d/init.tfa stop

Finally, If you think that I missed something "and of course there are still tons of tips that can boost the performance" please write it in the comment section. Remember to use above mentioned tips wisely and do NOT implement them on production databases to avoid getting bad Emails from HR 😁

 

References:

https://docs.oracle.com/cd/B28359_01/server.111/b28320/initparams246.htm#REFRN10219

https://docs.oracle.com/en/database/oracle/oracle-database/12.2/refrn/FAST_START_MTTR_TARGET.html#GUID-D2452F33-0FD8-4297-85EC-FF63A0F03499

https://docs.oracle.com/cd/E18283_01/server.112/e17110/initparams129.htm

https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/STATISTICS_LEVEL.html#GUID-16B23F95-8644-407A-A6C8-E85CADFA61FF

Cleanup Logs on Oracle RAC 12c+

$
0
0

 The following technical steps illustrate the cleanup of Oracle logs on Oracle Cluster system (Grid Infrastructure 12c and above).

Before actioning these steps, make sure that logs are no more required for troubleshooting errors neither required for auditing purposes.

Cleanup Database related logs:

The following commands should be executed against each database installed on the host replacing "orcl" with the actual database/instance name, and "racnode1" with the actual hostname.

Cleaning up database related logs can be done by executing the following command from ADRCI:

# adrci

adrci>show home
ADR Homes:
diag/rdbms/orcl/orcl1
diag/asm/+asm/+ASM1
diag/crs/racnode1/crs
diag/tnslsnr/racnode1/asmnet1lsnr_asm
diag/tnslsnr/racnode1/listener_scan1
diag/tnslsnr/racnode1/listener
diag/tnslsnr/racnode1/listener_scan3
diag/tnslsnr/racnode1/listener_scan2

adrci>set home diag/rdbms/orcl/orcl1
adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE
adrci>purge -age 0 -type LOG
adrci>purge -age 0 -type CDUMP
adrci>purge -age 0 -type UTSCDMP
adrci>purge -age 0 -type HM

Note: -age 0 means; remove all logs except the ones created in the recent hour, you can replace 0 with the number of hours back you want to keep logs.

This will cleanup the logs under the following directories:

SELECT name, value FROM v$diag_info where VALUE like '%rdbms%';

NAME                  VALUE
--------------------- -------------------------------------------
ADR Home              /u01/oracle/diag/rdbms/orcl/orcl1
Diag Trace              /u01/oracle/diag/rdbms/orcl/orcl1/trace
Diag Alert               /u01/oracle/diag/rdbms/orcl/orcl1/alert
Diag Incident         /u01/oracle/diag/rdbms/orcl/orcl1/incident
Diag Cdump           /u01/oracle/diag/rdbms/orcl/orcl1/cdump
Health Monitor      /u01/oracle/diag/rdbms/orcl/orcl1/hm
Default Trace File  /u01/oracle/diag/rdbms/orcl/orcl1/trace/orcl1_ora_31270.trc


Or you can manuallyremove the logs as follows:

# cd /u01/oracle/diag/rdbms/orcl/orcl1/alert; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/rdbms/orcl/orcl1/trace; du -sh .
# rm -f *.trm *.trc; ls -ltrh

# cd /u01/oracle/diag/rdbms/orcl/orcl1/cdump; du -sh .
# rm -rf *; ls -ltrh

# cd /u01/oracle/diag/rdbms/orcl/orcl1/incident; du -sh .
# rm -rf cdmp_*; rm -rf incdir_*; du -sh .

For audit logs, you have to delete them manually, but you have to perform the following workaround to avoid slowing down the DB during this activity:

# cd /u01/oracle/admin/orcl;ls -rtlh; du -sh *
# mv adump adump_old; mkdir adump; chmod o-rwx adump; ls -rtlh
# rm -rf adump_old

 

Cleanup ASM related logs:

Using ADRCI

adrci> set home diag/asm/+asm/+ASM1
adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE

For ASM audit logs, you have to delete them manually, using the same technique we used for cleaning up database audit logs to avoid performance degradation:

# cd /u01/grid/12.2.0.3/rdbms/audit; ls -rtlh; du -sh *
# mv adump adump_old; mkdir adump; chmod o-rwx adump; ls -rtlh
# rm -rf adump_old

 

Cleanup Grid Infrastructure related logs:

First, start with cleaning up listeners' logs

Using ADRCI:

adrci> show home
ADR Homes:
diag/rdbms/orcl/orcl1
diag/asm/+asm/+ASM1
diag/crs/racnode1/crs
diag/tnslsnr/racnode1/asmnet1lsnr_asm
diag/tnslsnr/racnode1/listener_scan1
diag/tnslsnr/racnode1/listener
diag/tnslsnr/racnode1/listener_scan3
diag/tnslsnr/racnode1/listener_scan2

adrci> set home diag/tnslsnr/racnode1/asmnet1lsnr_asm
adrci> purge -age 0 -type ALERT
adrci> purge -age 0 -type INCIDENT
adrci> purge -age 0 -type TRACE

adrci> set home diag/tnslsnr/racnode1/listener
adrci> purge -age 0 -type ALERT
adrci> purge -age 0 -type INCIDENT
adrci> purge -age 0 -type TRACE

adrci> set home diag/tnslsnr/racnode1/listener_scan1
adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE

adrci>set home diag/tnslsnr/racnode1/listener_scan2
adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE

adrci>set home diag/tnslsnr/racnode1/listener_scan3
adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE

Or instead of using ADRCI, you can cleanup the logs manually as follows:

# cd /u01/oracle/diag/tnslsnr/racnode1/listener/alert; ls -rtlh; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener/trace; ls -rtlh; du -sh .
# rm -f listener_*; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan1/alert; ls -rtlh; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan1/trace; ls -rtlh; du -sh .
# rm -f  listener_scan1_*.log; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan2/alert; ls -rtlh; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan2/trace; ls -rtlh; du -sh .
# rm -f  listener_scan2_*.log; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan3/alert; ls -rtlh; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/tnslsnr/racnode1/listener_scan3/trace; ls -rtlh; du -sh .
# rm -f  listener_scan2_*.log; ls -ltrh
 

Second, cleaning up clusterware logs:

Using ADRCI:

adrci>set home diag/crs/racnode1/crs

adrci>purge -age 0 -type ALERT
adrci>purge -age 0 -type INCIDENT
adrci>purge -age 0 -type TRACE
adrci>purge -age 0 -type LOG
adrci>purge -age 0 -type CDUMP

Or manually cleanup the clusterware logs:

# cd /u01/oracle/diag/crs/racnode1/crs/alert; du -sh .
# rm -f log_*.xml; ls -ltrh

# cd /u01/oracle/diag/crs/racnode1/crs/trace; du -sh .
# rm -f *.trm *.trc; ls -ltrh

# cd /u01/oracle/diag/crs/racnode1/crs/cdump; du -sh .
# rm -rf *; ls -ltrh

# cd /u01/oracle/crsdata/racnode1/trace/chad; du -sh .
# rm -f ochad.trc.{1..9}; ls -ltrh

Follow the same steps on the other RAC nodes.

Tools to help you out:

Cleanup Oracle logs script

Duplicate of a standby DB fails with ORA-39511: Start of CRS resource for instance '223' failed with error

$
0
0

Problem:

The Duplicate of a standby DB fails with the following error:

ORA-32006: CLUSTER_DATABASE initialization parameter has been deprecated
ORA-39511: Start of CRS resource for instance '223' failed with error:[CRS-5702: Resource 'ora.asm' is already running on 'ORCLDR_N1'
CRS-0223: Resource 'ora.asm' has placement error.
clsr_start_resource:260 status:223
clsrapi_start_asm:start_asmdbs status:223

Analysis:

The database which is being created is already exist on the same host, or it was dropped manually but still having some trace files that triggers above error.

Solution:

- If the database which is being restored is already exist then you should drop it first using DBCA which will take care of cleaning up all its files and resources from the Grid Infrastructure.
Note: DBCA is the only tool that can cleanly drop the databases that was created over an installed Grid Infrastructure, you shouldn't use SQLPLUS nor RMAN for that job, otherwise the database related GI resources will remain exist.

- If the database which is being restored was deleted using SQLPLUS or RMAN, you still can cleanup the DB by following these steps:

    - Run the following command to delete the DB if already registered with Grid Infrastructure:
      srvctl remove database -db ORCLDR -force -verbose
    - login to asmcmd console and delete all database related files including the spfile and the password file.
    - delete all database related files under $ORACLE_HOME/dbs.
    - Remove database entry from /etc/oratab.

 

Standby RAC Database Creation Steps 19c

$
0
0

Creation of a standby database in 19c is pretty simliar to 11g except of two points:

1- Using the compressed feature in the Duplicate command  "USING COMPRESSED BACKUPSET" can speed up the whole process by 200%. [12.2 New feature]

2- TEMPFILES will be created automatically whenStandby DB get opened in OPEN mode.

Before we start please pay attention to the following details of both Primary and Standby environments [Both are RAC environments]
EnvironmentNode NameDB_NAMEInstances_NamePublic IPVirtual IP (VIP)Private IP
Primary Node1ORCL_N1ORCLorcl1192.168.10.1Not in ScopeNot in Scope
Primary Node2ORCL_N2orcl2192.168.10.2Not in ScopeNot in Scope
Standby Node1ORCLDR_N1ORCLDRorcldr110.1.10.110.1.10.1010.110.10.1
Standby Node2ORCLDR_N2orcldr210.1.10.210.1.10.1110.110.10.2

As a matter of fact, Grid Infrastructure 19c should be already installed on both standby nodes, database software installation should be installed as well, you don't have to create a database.


Step 1: Modify the tnsnames.ora file [On both Primary nodes]:

 
This is to add two tnsentries, one for Primary DB "ORCL" and another for the Standby DB "ORCLDR".
# vi /u01/oracle/19c/network/admin/tnsnames.ora

ORCL =
  (DESCRIPTION =
    (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.1)(PORT=1521))
    (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.2)(PORT=1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )

ORCLDR=
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.1)(PORT=1521))
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.2)(PORT=1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ORCLDR)
    )
  )


Note: You can also Specify (UR=A) option next to service_name to connect to an instance in NOMOUNT mode: [this can work as an alternative to register the service statically with the listener, but it is not guaranteed to work all the time]
ORCLDR=
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.1)(PORT=1521))
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.2)(PORT=1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ORCLDR)
      (UR=A)
    )
  )



Step 2: Modify listener.ora: [On both Primary nodes]

To statically register the local instance SID:
[On Primary node1]
# vi /u01/grid/19c/network/admin/listener.ora

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC = (GLOBAL_DBNAME = orcl1) (ORACLE_HOME = /u01/oracle/19c) (SID_NAME = orcl1))
  )


# lsnrctl reload listener

[On Primary node2]
# vi /u01/grid/19c/network/admin/listener.ora

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC = (GLOBAL_DBNAME = orcl2) (ORACLE_HOME = /u01/oracle/19c) (SID_NAME = orcl2))
  )

# lsnrctl reload listener


Step 3: Modify tnsnames.ora  [On both Standby nodes]

This is to add two tnsentries, one for Primary DB "ORCL" and another for the Standby DB "ORCLDR".
# vi /u01/oracle/19c/network/admin/tnsnames.ora

ORCL =
  (DESCRIPTION =
    (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.1)(PORT=1521))
    (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.2)(PORT=1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )

ORCLDR=
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.1)(PORT=1521))
    (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.2)(PORT=1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ORCLDR)
    )
  )


Step 4: Modify listener.ora:  [On Standby node1]

Statically register the local instance SID:
# vi /u01/grid/19c/network/admin/listener.ora

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC = (GLOBAL_DBNAME = orcldr) (ORACLE_HOME = /u01/oracle/19c) (SID_NAME = orcldr1))
  )


# lsnrctl reload listener


* Do a TNSPING from both Primary and Standby nodes and make sure it's working.
# tnsping ORCL

# tnsping ORCLDR

Step 5: Make sure the Primary DB is in ARCHIVELOG & FORCE LOGGING modes: [On Primary DB]

SQL> ARCHIVE LOG LIST;
SQL> ALTER DATABASE FORCE LOGGING;
SQL> ALTER DATABASE ARCHIVE LOG CURRENT;

Make sure below 2 parameters are well configured to reflict the database name: [db_unique name on Primary DB should be orcl and on Standby DB it will  be orcldr]
SQL> show parameter db_unique_name
SQL> show parameter db_name

Step 6:Log Shipping Setup: [On Primary DB]

-- Here you should use the DB_UNIQUE_NAME of each of primary and standby:
SQL> ALTER SYSTEM SET LOG_ARCHIVE_CONFIG='DG_CONFIG=(orcl,orcldr)';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2='SERVICE=orcldr NOAFFIRM LGWR ASYNC delay=0 VALID_FOR=(all_logfiles,PRIMARY_ROLE) max_failure=0 reopen=300 net_timeout=90 DB_UNIQUE_NAME=orcldr';

-- Here you should use service names which you already configured earlier in tnsnames.ora:
SQL> ALTER SYSTEM SET log_archive_dest_state_2=enable;
SQL> ALTER SYSTEM SET remote_login_passwordfile=exclusive SCOPE=SPFILE;
SQL> ALTER SYSTEM SET fal_server='orcldr';
SQL> ALTER SYSTEM SET fal_client='orcl';
SQL> ALTER SYSTEM SET standby_file_management=auto;

Step 7:Create Standby REDOLOG Groups [On Primary DB]:

Standby REDOLOG groups should be same number as regular REDOLOG groups +1 for each thread. e.g. if the primary database has 5 REDOLOG groups for each thread, then I should create 6 Standby REDOLOG groups for each thread.

SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 1
     GROUP 10 ('+REDO1') SIZE 1g,
     GROUP 11 ('+REDO1') SIZE 1g,
     GROUP 12 ('+REDO1') SIZE 1g,
     GROUP 13 ('+REDO1') SIZE 1g,
     GROUP 14 ('+REDO1') SIZE 1g,
     GROUP 15 ('+REDO1') SIZE 1g;



SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 2
     GROUP 16 ('+REDO2') SIZE 1g,
     GROUP 17 ('+REDO2') SIZE 1g,
     GROUP 18 ('+REDO2') SIZE 1g,
     GROUP 19 ('+REDO2') SIZE 1g,
     GROUP 20 ('+REDO2') SIZE 1g,
     GROUP 21 ('+REDO2') SIZE 1g;
    

Step 8:Make sure the SNAPSHOT controlfile directory is exist and writable on both Primary nodes: [Even if the location is not shared between both nodes!]

# rman
RMAN> show all;
RMAN> CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/acfs/backup/sprint/snapcf_sprint.f';

Step 9:Create the password file on [Primary node1]

# orapwd file=/u01/oracle/19c/dbs/orapworcl1 password=Pass#0rd entries=10


If the Password file is already exist on ASM, then Copy it to $ORACLE_HOME/dbs:

[To make it seamless reset the SYS password on both Primary Instances]

SQL> alter user sys identified by "Pass#0rd";


# srvctl config database -d orcl | grep pwd
+DATA/ORCL/PASSWORD/pwdorcl.256.1039797083

# asmcmd cp +DATA/ORCL/PASSWORD/pwdorcl.256.1039797083 $ORACLE_HOME/dbs/orapworcl1

Copy the password file to [Primary Node2]:
# scp -p orapworcl1 oracle@192.168.10.2:/u01/oracle/19c/dbs/orapworcl2

Copy the password file to [Standby Node1]
# scp -p orapworcl1 oracle@10.1.10.1:/u01/oracle/19c/dbs/orapworcldr1

Copy the password file to [Standby Node2]
# scp -p orapworcl1 oracle@10.1.10.2:/u01/oracle/19c/dbs/orapworcldr2


Step 10:Create the pfile on Target: [on Standby node1]

# vi $ORACLE_HOME/dbs/initorcldr1.ora

*.sga_target=5g
*.pga_aggregate_target=2g
*.control_files=+DATA,+REDO1,+REDO2
*.db_create_file_dest='+DATA'
*.db_create_online_log_dest_1='+REDO1'
*.db_create_online_log_dest_2='+REDO2'
*.db_name='orcldr'
*.db_recovery_file_dest='+RECO'
*.db_recovery_file_dest_size=900g
*.db_unique_name='orcldr'
*.remote_login_passwordfile='exclusive'



Step 11:Create Directory Structure: [Similar to what to be configured on PFILE and DBA_DIRECTORIES] [on both Standby nodes]

[Standby node1]
# mkdir -p /u01/oracle/admin/orcldr/adump
# mkdir -p /u01/oracle/diag/rdbms/orcldr1

[Standby node2]
# mkdir -p /u01/oracle/admin/orcldr/adump
# mkdir -p /u01/oracle/diag/rdbms/orcldr2

Step 12:Start the new orcldr1 instance in nomount mode with pfile: [on Standby nodes1]

# cd $ORACLE_HOME/dbs
# export ORACLE_SID=orcldr1
# sqlplus "/ as sysdba"
SQL> startup nomount pfile=initorcldr1.ora

Step 13:Test the connection between Primary and Standby instances:

-- From [Primary node1] try to connect to the standby instance:
SQL> conn sys/Pass#0rd@orcldr as sysdba
connected

-- From [Primary node2] try to connect to the standby instance:
SQL> conn sys/Pass#0rd@orcldr as sysdba
connected

-- From [Standby node1] try to connect to the Primary DB:
SQL> conn sys/Pass#0rd@orcl as sysdba
connected

 
Step 14:Create the RMAN Duplicate script: [On Primary node1]
 
# vi ~/duplicate_orcldr_standby.rman

run {
allocate channel disk1 type disk;
allocate channel disk2 type disk;
allocate channel disk3 type disk;
allocate auxiliary channel aux1 type disk;
allocate auxiliary channel aux2 type disk;
allocate auxiliary channel aux3 type disk;
duplicate target database for standby from active database USING COMPRESSED BACKUPSET
spfile
parameter_value_convert 'ORCL','ORCLDR'
set db_name='orcl'
set db_unique_name='orcldr'
set cluster_database='FALSE'
set control_files='+DATA','+REDO1','+REDO2'
set db_create_file_dest='+DATA'
set db_create_online_log_dest_1='+REDO1'
set db_create_online_log_dest_2='+REDO2'
set db_name='orcl'
set db_recovery_file_dest='+RECO'
set db_recovery_file_dest_size='900G'
set sga_target='5g'
set db_cache_size='2g'
set shared_pool_size='1g'
set pga_aggregate_target='2g'
set remote_login_passwordfile='exclusive'
set instance_number='1'
set audit_file_dest='/u01/oracle/admin/orcldr/adump'
set diagnostic_dest='/u01/oracle'
set db_file_name_convert='+DATA/orcl/datafile','+DATA/orcldr/datafile','+DATA/orcl/tempfile','+DATA/orcldr/tempfile'
set log_file_name_convert='+REDO1/orcl/onlinelog','+REDO1/orcldr/onlinelog','+REDO2/orcl/onlinelog','+REDO2/orcldr/onlinelog'
set db_create_file_dest='+DATA'
set fal_client='orcldr'
set fal_server='orcl'
set standby_file_management='AUTO'
set log_archive_config='dg_config=(orcldr,orcl)'
set log_archive_dest_2='SERVICE=orcl NOAFFIRM LGWR ASYNC delay=0 VALID_FOR=(all_logfiles,PRIMARY_ROLE) max_failure=0 reopen=300 net_timeout=90 DB_UNIQUE_NAME=orcl';
}


Note: Using COMPRESSION with duplicate command will speed up the duplicate by 200% in average]

Step 15:Run the Duplicate operation: [From Primary node1]

Note: Don't connect "TARGET /" nor "AUXILIARY /", you have to connect using ID and password and SERVICE NAME i.e: sys/Pass#0rd@ORCLDR

# export ORACLE_SID=orcl1
# nohup $ORACLE_HOME/bin/rman target sys/Pass#0rd@ORCL auxiliary sys/Pass#0rd@ORCLDR cmdfile=~/duplicate_orcldr_standby.rman | tee ~/duplicate_standby.log 2>&1 &

Step 16:  Recover the Standby DB: [on Standby node1]

SQL> SHUTDOWN IMMEDIATE
SQL> STARTUP

Note: The database will not open unless it apply all the pending archivelogs. [This happens AUTOMATICALLY]

Step 17:Disable log_archive_dest_state_2 & 3: [on Standby DB]

SQL> ALTER SYSTEM SET log_archive_dest_state_2=defer;
SQL> ALTER SYSTEM SET log_archive_dest_state_3=defer;
SQL> ALTER SYSTEM SET dispatchers = "(PROTOCOL=TCP) (SERVICE=orcldrXDB)";

Step 18:Create Standby REDOLOG Groups [on Standby DB]:

Same number of Standby REDOLOG groups on Primary should be created on Standby DB as well:

SQL> RECOVER MANAGED STANDBY DATABASE CANCEL;

SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 1
     GROUP 10 ('+REDO1') SIZE 1g,
     GROUP 11 ('+REDO1') SIZE 1g,
     GROUP 12 ('+REDO1') SIZE 1g,
     GROUP 13 ('+REDO1') SIZE 1g,
     GROUP 14 ('+REDO1') SIZE 1g,
     GROUP 15 ('+REDO1') SIZE 1g;


SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 2
     GROUP 16 ('+REDO2') SIZE 1g,
     GROUP 17 ('+REDO2') SIZE 1g,
     GROUP 18 ('+REDO2') SIZE 1g,
     GROUP 19 ('+REDO2') SIZE 1g,
     GROUP 20 ('+REDO2') SIZE 1g,
     GROUP 21 ('+REDO2') SIZE 1g;

    
Step 19: Turn ON Flashback [On Standby DB]:

SQL> ALTER DATABASE FLASHBACK ON;
SQL> RECOVER MANAGED STANDBY DATABASE NODELAY DISCONNECT;

Note: "USING CURRENT LOGFILE" in the Recover command is not required anymore in 19c.

Step 20: Restart log_archive_dest_state_2 [On Primary DB]:
This to refresh the redo log shipping process on promary DB and fix any gap.

SQL> ALTER SYSTEM SET log_archive_dest_state_2=defer;
SQL> ALTER SYSTEM SET log_archive_dest_state_2=enable;

Step 21: Start the Recovery process [On Standby DB]:

SQL> RECOVER MANAGED STANDBY DATABASE NODELAY DISCONNECT;

Step 22: Fix RMAN Settings [On Standby DB]:

RMAN> CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY;
RMAN> CONFIGURE BACKUP OPTIMIZATION ON;
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/acfs/backup/ORCLDR/%F';
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE 'SBT_TAPE' TO '%F';
RMAN> CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/acfs/backup/ORCLDR/snapcf_orcldr.f';

[On bothStandby Nodes] Create the full path for the CONTROLFILE SNAPSHOT BACKUP: [It should be a shared location between both nodes, but if this not possible for any reason just create it locally on both nodes with the right permissions]
# mkdir -p /acfs/backup/ORCLDR
# chown oracle:oinstall -R /acfs/backup

Step 23: Configure the archivelog deletion policy [On Primary DB]:

RMAN> CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY;

Step 24: Convert the standby to RAC DB [On Standby node1]:

SQL>ALTER SYSTEM SET cluster_database=true SCOPE=SPFILE;
    ALTER SYSTEM SET cluster_database_instances=2 SCOPE=SPFILE SID='*';
    ALTER SYSTEM SET instance_number=1         SCOPE=SPFILE SID='orcldr1';
    ALTER SYSTEM SET instance_number=2           SCOPE=SPFILE SID='orcldr2';
    ALTER SYSTEM SET thread=1                  SCOPE=SPFILE SID='orcldr1';
    ALTER SYSTEM SET thread=2                  SCOPE=SPFILE SID='orcldr2';
    ALTER SYSTEM SET undo_tablespace=UNDOTBS1  SCOPE=SPFILE SID='orcldr1';
    ALTER SYSTEM SET undo_tablespace=UNDOTBS2  SCOPE=SPFILE SID='orcldr2';
    ALTER SYSTEM SET cluster_interconnects='10.110.10.1' SCOPE=SPFILE SID='orcldr1';
    ALTER SYSTEM SET cluster_interconnects='10.110.10.2' SCOPE=SPFILE SID='orcldr2';
    ALTER SYSTEM SET local_listener='(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.10)(PORT=1521))' sid='orcldr1';
    ALTER SYSTEM SET local_listener='(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.10.11)(PORT=1521))' sid='orcldr2';


Create the SPFILE on a shared location between Standby RAC Nodes which is +DATA:
SQL>create pfile='/u01/oracle/19c/dbs/initorcldr.ora' from spfile;
SQL>create spfile='+DATA' from pfile='/u01/oracle/19c/dbs/initorcldr.ora';

Get the spfile full path on ASM using asmcmd to use it in the next step:
# asmcmd ls -lst +DATA/ORCLDR/PARAMETERFILE
+DATA/ORCLDR/PARAMETERFILE/spfile.345.1040975313

Register the database with clusterware services:
# srvctl add database -db orcldr -oraclehome /u01/oracle/19c -dbtype RAC -spfile +DATA/ORCLDR/PARAMETERFILE/spfile.345.1040975313 \
-role PHYSICAL_STANDBY -startoption open -stopoption immediate -diskgroup "DATA,REDO1,REDO2,RECO" -policy AUTOMATIC -verbose


Register the instances with clusterware services:
# srvctl add instance -db orcldr -instance orcldr1 -node ORCLDR_N1
# srvctl add instance -db orcldr -instance orcldr2 -node ORCLDR_N2

Shutdown the DB [on Standby node1]:
SQL>  shutdown immediate;

Test Startup/Stop of the Standby DB [On Both Standby nodes]
# srvctl start database -db orcldr
# srvctl stop  database -db orcldr
# srvctl start database -db orcldr

*Make sure the Redo log files is being shipped from Primary to Standby whenever any of the standby instances are down.

Start the Recovery Process: [On any of Standby nodes]
SQL> RECOVER MANAGED STANDBY DATABASE NODELAY DISCONNECT;

Lastly: You can use the following scripts to complete your setup:

Configure LAG monitoring

Setup Archive deletion script

In case you have a need to create many standby DBs, this script can help you out: https://github.com/asiandevs/PhysicalStandbyWithDGBroker

Viewing all 214 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>