Tuesday, 30 July 2013

Identifying data pump jobs to be /Kill/Stop/Resume


Do a select from dba_datapump_jobs in sqlplus to get the job name:

> expdp system full=y

SELECT owner_name, job_name, operation, job_mode, state
FROM dba_datapump_jobs;

OWNER_NAME JOB_NAME             OPERATION  JOB_MODE   STATE
---------- -------------------- ---------- ---------- ------------
SYSTEM     SYS_EXPORT_FULL_01   EXPORT     FULL       EXECUTING

Or when you use the JOB_NAME parameter when datapumping, you already identified the job with a name. You don’t need to look up afterwards…

expdp system full=y JOB_NAME=EXP_FULL

OWNER_NAME JOB_NAME             OPERATION  JOB_MODE   STATE
---------- -------------------- ---------- ---------- ------------
SYSTEM     EXP_FULL             EXPORT     FULL       EXECUTING


Killing or stopping a running datapump job:

The difference between Kill and Stop is simple to explain. When killing a job, you won’t be able to resume or start it again. Also logs and dumpfiles will be removed!
When exporting (or importing), press Ctrl-c to show the datapump prompt and type KILL_JOB orSTOP_JOB[=IMMEDIATE]. You will be prompted to confirm if you are sure…
Adding ‘=IMMEDIATE‘ to STOP_JOB will not finish currently running ‘sub-job’ and must be redone when starting it again.

Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
[Ctrl-c]

Export> KILL_JOB

..or..

Export> STOP_JOB=IMMEDIATE
Are you sure you wish to stop this job ([yes]/no): yes

Resuming a stopped job:

Identify your job with SQL or you already knew it because you used ‘JOB_NAME=‘ ;)
SELECT owner_name, job_name, operation, job_mode, state
FROM dba_datapump_jobs;

OWNER_NAME JOB_NAME             OPERATION  JOB_MODE   STATE      
---------- -------------------- ---------- ---------- ------------
SYSTEM     EXP_FULL             EXPORT     FULL       NOT RUNNING
Now we can ATTACH to the job using it as a parameter to the expdp or impdp command, and a lot of gibberish is shown:

> expdp system ATTACH=EXP_FULL

Job: EXP_FULL
 Owner: SYSTEM
 Operation: EXPORT
 Creator Privs: TRUE
 GUID: A5441357B472DFEEE040007F0100692A
 Start Time: Thursday, 08 June, 2011 20:23:39
 Mode: FULL
 Instance: db1
 Max Parallelism: 1
 EXPORT Job Parameters:
 Parameter Name      Parameter Value:
 CLIENT_COMMAND        system/******** full=y JOB_NAME=EXP_FULL
 State: IDLING
 Bytes Processed: 0
 Current Parallelism: 1
 Job Error Count: 0
 Dump File: /u01/app/oracle/admin/db1/dpdump/expdat.dmp
 bytes written: 520,192

Worker 1 Status:
 Process Name: DW00
 State: UNDEFINED
(Re)start the job with START_JOB, use ‘=SKIP_CURRENT‘ if you want to skip the current job. To show progress again, type CONTINUE_CLIENT (Job will be restarted if idle).
Export> START_JOB[=SKIP_CURRENT]
Export> CONTINUE_CLIENT
Job EXP_FULL has been reopened at Thursday, 09 June, 2011 10:26
Restarting "SYSTEM"."EXP_FULL":  system/******** full=y JOB_NAME=EXP_FULL

Processing object type DATABASE_EXPORT/TABLESPACE

Processing object type DATABASE_EXPORT/PROFILE

Monday, 29 July 2013

How to delete or remove non executing data pump jobs in oracle

 step 1- Identify which jobs are not in running state


SET lines 200

SELECT owner_name, job_name, operation, job_mode,
state, attached_sessions
FROM dba_datapump_jobs
ORDER BY 1,2;

output:

OWNER_NAME       JOB_NAME       OPERATION
------------------------------ ------------------------------ ------------------------------------------------------------------------------------------------------------------------
JOB_MODE STATE ATTACHED_SESSIONS
------------------------------------------------------------------------------------------------------------------------ ------------------------------ -----------------
MANJIT       SYS_EXPORT_FULL_01       EXPORT
FULL NOT RUNNING 0

MANJIT       SYS_EXPORT_FULL_02       EXPORT
FULL NOT RUNNING 0

MANJIT       SYS_EXPORT_FULL_03       EXPORT
FULL NOT RUNNING 0


OWNER_NAME       JOB_NAME       OPERATION
------------------------------ ------------------------------ ------------------------------------------------------------------------------------------------------------------------
JOB_MODE STATE ATTACHED_SESSIONS
------------------------------------------------------------------------------------------------------------------------ ------------------------------ -----------------
MANJIT       SYS_EXPORT_FULL_04       EXPORT
FULL NOT RUNNING 0

Step 2- Identify the master tables which are created for these jobs

select 
   o.status, 
   o.object_id, 
   o.object_type, 
   o.owner||'.'||object_name "OWNER.OBJECT" 
from 
   dba_objects o, 
   dba_datapump_jobs j 
where 
   o.owner=j.owner_name 
and 
   o.object_name=j.job_name 
and 
   j.job_name not like 'BIN$%' 
order by 4, 2; 

output:

STATUS OBJECT_ID OBJECT_TYPE       OWNER.OBJECT
------- ---------- ------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------
VALID     123893 TABLE       MANJIT.SYS_EXPORT_FULL_01
VALID     123993 TABLE       MANJIT.SYS_EXPORT_FULL_02
VALID     124093 TABLE       MANJIT.SYS_EXPORT_FULL_03
VALID     124193 TABLE       MANJIT.SYS_EXPORT_FULL_04

Step -3 Drop these master tables

SQL> drop table        MANJIT.SYS_EXPORT_FULL_03;

Table dropped.

SQL> drop table        MANJIT.SYS_EXPORT_FULL_02;

Table dropped.

SQL> drop table        MANJIT.SYS_EXPORT_FULL_01;

Table dropped.
Important points

1. Datapump jobs that are not running doesn’t have any impact on currently executing ones.
2. When any datapump job (either export or import) is initiated, master and worker processes will be created.
3. When we terminate export datapump job, master and worker processes will get killed and it doesn’t lead to data courrption.

4. But when import datapump job is terminated, complete import might not have done as processes(master & worker)  will be killed.

Friday, 26 July 2013

Fix-ORA-39014


 

  ORA-39014: One or more workers have prematurely exited.




Solution:

1. If available for your Platform Download Patch 5879865 to resolve this issue. 

2. In the meantime, please use one of the following as a workaround:
* set both of the following in the init/spfile

o "_complex_view_merging" = false
o event="38066 trace name context forever, level 1" or level 2

OR

* set "_optimizer_cost_based_transformation"=off
 
Hope it do wonders !!!!!

Thursday, 25 July 2013

Upgrade Oracle Database using DBUA

Upgrade Oracle Database using DBUA

Steps to Upgrade an Oracle database
11.2.0.1.0
11- Is a major database release number
2- Is a database maintenance release number
0- Is a application server release number
1- Is a component specific release number/Patchset number
0- Is a platform specific release number

If you upgrade/migrate the database, the FIRST number and the SECOND number will changes. TheFOURTH digit indicate the patchset number, this number will change whenever you apply the patchsets to the database.
We can use below steps to upgrade from below Oracle versions to a higher Oracle Version (10gr1, 10gr2, 11gr1 and 11gr2)

9.2.0.4 or higher release   -> 10gr1, 10gr2, 11gr1 and 11gr2
 10.1.0.2 or higher            ->   10gr2, 11gr1 and 11gr2
 10.2.0.1 or higher            ->   11gr1 and 11gr2
 11.1.0.6 or higher            ->   11gr2 and 12c

Oracle Upgrade Summary
1)      Must install the new Oracle version in separate ORACLE_HOME to which we are upgrading the database.
2)      Both the old Oracle Version and New/Upgraded Oracle Version software must be installed properly before starting the upgrade.
3)      Take the backup of database before starting the upgrade.
4)      Before starting the upgrade Run the pre upgrade script from new $ORACLE_HOME/rdbms/admin
utlu112i.sql      11.2
utlu111i.sql      11.1
utlu102i.sql      10.2
utlu101i.sql      10.1
5)  Run the database upgrade from New Oracle Home using
DBUA
or
catupgrd.sql  (Manual Upgrade )
6)      Once the upgrade is complete validate the upgrade using Post Upgrade Script  from new ORACLE_HOME/rdbms/admin/
utlu112s.sql      11.2
utlu111s.sql      11.1
utlu102s.sql      10.2
utlu101s.sql      10.1

Oracle Upgrade Detailed Steps
Note: The steps in this document can be used to upgrade a 9i/10gr1/10gr2/11gr1 to 10gr1/10gr2/11gr1/11gr2.
In this document we are upgrading from 11gr1 to 11gr2 so both software must be installed and 11gr1 database with ORACLE_SID=orcl must be present before we start the upgrade.
Our Example will use
11gr1 ORACLE_HOME=/u01/app/oracle/product/11g
11gr1 ORACLE_SID=orcl
11gr2 ORACLE_HOME=/u01/app/oracle/product/11gr2

Steps
1) Shutdown the database
2) Take a comple backup of datafiles,controlfiles, redo logfiles, Spfile/pfile and password file.The complete backup of database is needed to revert back if the Database upgrade fails.

A) Pre upgrade Steps
Copy the preupgrade script to any temp location for example /u01/app/oracle
cp /u01/app/oracle/product/11gr2/rdbms/admin/utlu112i.sql /u01/app/oracle
cd /u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/11g
export ORACLE_SID=orcl
If you are upgrading to 11gr2 run below script
@utlu112i.sql
If you are upgrading to 11gr1 run below script
@ utlu111i.sql
If you are upgrading to 10gr2 run below script
@ utlu102i.sql

Below we are spooling to a log file so that we have the pre upgrade validations stored in upgrade_info.log file that we can refer later.
sql>      spool upgrade_info.log
sql>      @utlu112i.sql
sql>      spool off
The Pre upgrade script suggest any database changes that needs to be done before starting the Database Upgrade using DBUA or catupgrd.sql Script.
The pre upgrade script validates following information:
  • Database version.
  • Tablespace sizes.
  • Updated, renamed and deprecated initialization parameters.
  • Init.ora or Spfile Parameters that needs to be resize before starting the actual upgrade. ( This step should not be ignored)
  • Database Components that will be upgraded or installed
  • SYSAUX tablespace present (if missing).
  • Miscellaneous Warnings
    • Warning for Old Timezone
    • Warning for Stale Optimizer Statistics
    • Warning for EM Database Control Repository
Note: Each of the warning suggested by Pre Upgrade tool must be fixed.
Fix all the issues reported by Pre-upgrade script before starting DBUA

B) Upgrade Steps
(Two Methods to do the actual Database Upgrade, either use DBUA
or catupgrd.sql (manual method)  which has many steps but it is more flexible)
Oracle recommends using DBUA to upgrade database.
1. Login in as Oracle 11g user, and initiate all the variables need for the environment
$ export ORACLE_BASE=/u01/app/o11g
$ export ORACLE_HOME=/u01/app/o11g/product/11.1.0/db_1
$ export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
$ export PATH=$ORACLE_HOME/bin:$PATH
2. Confirm the Oracle 10g database name and ORACLE_HOME path is entered in /etc/oratab file
$ cat /etc/oratab
orcl:/u01/app/o10g/product/10.2.0/db_1:N
3. Execute the dbca utility from Oracle 11g’s path
$ $ORACLE_HOME/bin/dbua
export ORACLE_SID=orcl
Run the DBUA from New 11gr2 ORACLE_HOME/bin
$ cd /u01/app/oracle/product/11gr2/bin
$./dbua
Once the DBUA (Database Upgrade Assistant) GUI starts. Follow below points to upgrade the database. DBUA takes about 60 minutes to complete even for very large databases.
  • Select the Database that needs to be upgraded.
  • If the database name that needs to be upgraded is not present in DBUA,
Add the entry $ORACLE_SID:$ORACLE_HOME:N to /etc/oratab
For Example: ora11g:/u01/app/oracle/product/orcl:N
Note: The $ORACLE_HOME should be the old oracle home that is getting  upgraded.
  • Oracle 11g requires the “Diagnostic Destination”. Set diagnostic destination to oracle base.
  • Select “Do not move Database as part of upgrade”
  • Do not specify Flash Recovery Area option
  • Select “Configure database with Enterprise Manager” or Database Control if required.
  • Select “Recompile Invalid objects at the end of upgrade” options in dbua
  • Do not select the backup option if we have already have taken backup before starting Database Upgrade, Also it is not needed if we already have RMAN backup.
C) Post Upgrade Steps
Once the upgrade is complete modify the profile file to use the new ORACLE_HOME
Run the post upgrade script to validate the upgrade using new ORACLE_HOME
SQL> @$ORACLE_HOME/rdbms/admin/utlu112s.sql
SQL> @/u01/app/oracle/product/11gr2/rdbms/admin/utlu112s.sql

This completes the Oracle upgrade from 11gr1 to 11gr2 for orcl database!!!!
———————————————————————————-

Miscellaneous Commands that may be required before running DBUA
Sometimes the Pre Upgrade tool (utlu112i.sql) complains that some pre steps needs to be done before starting the Database Upgrade. Few of these Miscellaneous Warnings can be fixed by using below commands:

SQL> SHOW PARAMETER JAVA_POOL_SIZE
ALTER SYSTEM SET JAVA_POOL_SIZE=200M sid=’orcl’;
SQL> EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;
SQL> PURGE DBA_RECYCLEBIN;

SQL>
exec dbms_stats.gather_schema_stats(‘SYS‘,options=>’GATHER’, -
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, -
method_opt => ‘FOR ALL COLUMNS SIZE AUTO’, cascade => TRUE);
SQL>
exec dbms_stats.gather_schema_stats(‘WKSYS‘,options=>’GATHER’, -
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, -
method_opt => ‘FOR ALL COLUMNS SIZE AUTO’, cascade => TRUE);
SQL>
exec dbms_stats.gather_schema_stats(‘SYSMAN‘,options=>’GATHER’, -
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, -
method_opt => ‘FOR ALL COLUMNS SIZE AUTO’, cascade => TRUE);
SQL>
exec dbms_stats.gather_schema_stats(‘OLAPSYS‘,options=>’GATHER’, -
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, -
method_opt => ‘FOR ALL COLUMNS SIZE AUTO’, cascade => TRUE);

Monday, 22 July 2013

FIX- ORA-03113: end-of-file on communication channel


Process ID: 12400
Session ID: 96 Serial number: 3

Solution:

1.Check your alert log file

One of the suggested action is to look in the alert.log file.  To find the location of alert.log, you do:
  1. Find the location of diagnostic destination from the initialization parameter file (i.e., dbs/init<sid>.ora ).  For example, we have this entry:
    • diagnostic_dest=/slot/fiz7865/log

  2. From there, you can find alert.log file in the following sub directory:
    • <diagnostic_dest>/diag/rdbms/<dbname>/<instname>/trace

In the alert_<sid>.log, we have found the following messages:

-rw-r----- 1 oracle oinstall 178164407 Jul 22 15:51 alert_app.log

[oracle@exilant trace]$ tail -200 alert_app.log

Output of alert log file:

Errors in file /opt/app/oracle/diag/rdbms/apple/apple/trace/apple_arc3_3238.trc:
ORA-19809: limit exceeded for recovery files
ORA-19804: cannot reclaim 18179072 bytes disk space from 4070572032 limit
ARC3: Error 19809 Creating archive log file to '/opt/app/oracle/flash_recovery_area/APPLE/archivelog/2013_03_10/o1_mf_1_615_%u_.arc'
Sun Mar 10 16:05:32 2013
Errors in file /opt/app/oracle/diag/rdbms/apple/apple/trace/apple_arc0_3201.trc:
ORA-19815: WARNING: db_recovery_file_dest_size of 4070572032 bytes is 100.00% used, and has 0 remaining bytes available.
************************************************************************
You have following choices to free up space from recovery area:
1. Consider changing RMAN RETENTION POLICY. If you are using Data Guard,
   then consider changing RMAN ARCHIVELOG DELETION POLICY.
2. Back up files to tertiary device such as tape using RMAN
   BACKUP RECOVERY AREA command.
3. Add disk space and increase db_recovery_file_dest_size parameter to
   reflect the new space.
4. Delete unnecessary files using RMAN DELETE command. If an operating
   system command was used to delete files, then use RMAN CROSSCHECK and
   DELETE EXPIRED commands.
************************************************************************
Errors in file /opt/app/oracle/diag/rdbms/apple/apple/trace/apple_arc0_3201.trc:
ORA-19809: limit exceeded for recovery files
ORA-19804: cannot reclaim 18179072 bytes disk space from 4070572032 limit
ARC0: Error 19809 Creating archive log file to '/opt/app/oracle/flash_recovery_area/APPLE/archivelog

2. Go to SQLPLUS

         SQL> startup                                         — Failed to startup, the same ORA-03113 Error
 SQL> startup nomount                          — ORACLE Instance Started
 SQL> alter database mount                   — Database altered
 SQL> exit
 $ rman target /
 RMAN> crosscheck archivelog all      — Here you will see all the names of archivelogs still exist
 RMAN> delete expired archivelog all
 RMAN> exit
 $ sqlplus / as sysdba
 SQL> alter database open                    — Database altered
$ ps -ef | grep pmon
oracle   12734     1  0 16:10 ?        00:00:00 ora_pmon_app
oracle   12880 12257  0 16:12 pts/5    00:00:00 grep pmon



Monday, 15 July 2013

Fix-Heartbeat failed to connect to standby 'prm'. Error is 1031 ORA-01031: insufficient privileges

Error 1031 received logging on to the standby
ORA-01031: insufficient privileges

Heartbeat failed to connect to standby 'prm'. Error is 1031


For the redo transfer to take place efficiently, the password file on standby should be a copy from the primary and renamed standby.We can use v$pwd_file_users data dictionary view to check if the password file is used
1.copy the password file from the primary to the standby and renamed the password file in the following format ie orapw<sid> . 

2.Restart the media recovery process on the standby. 

Once the above steps are completed we could see that redo shipping and redo apply is taking place.

Copy the latest Password file from available PRIMARY Node to rest of PRIMARY and STANDBY nodes:
---------------------------------------------------------------------------------------------- 
Primary (Node 1)
----------------
cd $ORACLE_HOME/dbs
ls -lrt
scp orapw<sid> oracle@PROD_NODE_2_hostname:/oracle/home/dbs

scp orapw<sid> oracle@DR_NODE_1_hostname:/oracle/home/dbs
scp orapw<sid> oracle@DR_NODE_2_hostname:/oracle/home/dbs

or

DR
==
select * from gv$pwfile_users;

we have to check sec_case_sensitive_logon parameter on primary and standby.
SQL> show parameter sec_case_sensitive_logon;

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
sec_case_sensitive_logon boolean FALSE
SQL>

We have to recreate the passwd file or copy Primary server to Standby server.
In cause sec_case_sensitive_logon parameter value is true, we have to use below orapwd command.
orapwd file=$ORACLE_HOME/dbs/orapwPROD password=password123 entries=10 ignorecase=y

In cause sec_case_sensitive_logon parameter value is false, we have to use below orapwd command.
orapwd file=$ORACLE_HOME/dbs/orapwPROD password=password123 entries=10

DR
==
cancelling mrp process:
alter database recover managed standby database cancel;

starting mrp process:
alter database recover managed standby database disconnect from session;

select inst_id,process,status,thread#,sequence#,block#,blocks from gv$managed_standby; 

Thursday, 11 July 2013

FIX- ORA-00119: invalid specification for system parameter LOCAL_LISTENER ORA-00132: syntax error or unresolved network name 'db11g'

EASY fix.

Instead of spfile, start your database from pfile, and if the database starts then create a new spfile from it. 

Otherwise remove the local_listener parameter from the pfile and spfile and try starting it. 

$ cd $ORACLE_HOME/dbs
$  ls -rt
$ vi initdb11g.ora

and remove 
*.local_listener='db11g'

$ vi spfiledb11g.ora

and remove 
*.local_listener='db11g'

$ sqlplus / as sysdba

SQL> startup;
ORACLE instance started.

Total System Global Area  830930944 bytes
Fixed Size    2217912 bytes
Variable Size  641730632 bytes
Database Buffers  180355072 bytes
Redo Buffers    6627328 bytes
Database mounted.
Database opened.

SQL> select name from v$database;

NAME
---------
DB11G

Wonders!!!!!



Thursday, 27 June 2013

How to give read only access to the tables in a schema

Create a user

SQL> create user b identified by b;

User created.

SQL> grant select  table,create session to b;


From target schema idl

SQL>conn idl/idl;
connected
sql>GRANT SELECT ON AUDIRAIL TO b ;

From source schema

sql>conn b/b;
connected

SQL>  select * from idl.audirail;



select * from tab where tname = 'AUDIRAIL';

You can write a simple procedure to achieve this :

set serveroutput on
DECLARE
sql_txt VARCHAR2(300);
CURSOR tables_cur IS
SELECT table_name 
FROM dba_tables 
 where owner='idl'
  and table_name in ('audirail', 'audirail2') ;
BEGIN 
dbms_output.enable(10000000);
FOR tables IN tables_cur LOOP
sql_txt:='GRANT SELECT ON '||audirail|| TO GPS;
execute immediate sql_txt;
END LOOP;
END;
/



FIX-EXP-00011 Easily


I had to export only tables from a schema

My export script:

exp sys/oracle file=home/oracle/PT_ow1.dmp log=/home/oracle/PT_ow1.log tables=manju1,manju2 rows=yes indexes=yes

Error
EXP-00011

Tried Datapump :But some different error


Solution:Point your schema name to that particular tablename

example
tables=schemaname.tablename ,schemaname.tablename

My modified export script:


exp sys/oracle file=home/oracle/PT_ow1.dmp log=/home/oracle/PT_ow1.log tables=pt_ow.manju1,pt_ow.manju2 rows=yes indexes=yes


It worked"

Friday, 21 June 2013

FIX-ORA-01940:Cannot drop a user that is currently connected.


SQL> drop user manju cascade;

*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected

Solution of The Problem:

Find out the connected user sid and serial# by,

SQL> select sid, serial# from v$session where username = 'manju';

   SID    SERIAL#
---------- ----------
   268       1268
   315       1223

Before killing session you may wish to lock the account for further connection attempts. This is extremely necessary to drop a user who automatically establish session like to drop an application user or to drop a user who perform batch jobs.

SQL> Alter user manju account lock;

Now kill the connected session.
SQL> alter system kill session '268,1268';
System altered.

SQL> alter system kill session '315,1223';

System altered.

And then drop the user.
SQL> drop user manju cascade;
User dropped.

Wednesday, 12 June 2013

How to Begin Performance Tuning

 How to Begin Performance Tuning

  By Arup Nanda Oracle ACE Director

Nice article to refer.

Resolve session performance issues in Oracle Database.
It’s the middle of the night, and you get a frantic call from someone complaining that the database is slow. The caller demands to know why—and what you’re going to do about it. Sound familiar? If it does, you are not alone. High performance is a common expectation of database system users: they get very unhappy when they don’t get it, and they are usually not shy about letting you know. What should you do next? In this article, you will learn some techniques for troubleshooting Oracle Database performance issues.
To use the scripts in this article, you need to create some tables in a test schema and access some dynamic performance views. The database user SYS has all privileges to access the views, so you need the password for the SYS user. The script for setting up the example tables is available in the sidebar.

Session State

Setup


To set up the test cases for this article, execute the SQL in this “Setup” section. The SQL assumes that you have access to the SYS user, you can create a user called ARUP (which means you don’t have a user with the same name), and you have a tablespace called USERS with at least 64 KB of free space.

Connect as SYS, and execute the following:

connect sys/<password> as sysdba

create user arup identified by arup
default tablespace users
/

alter user arup quota unlimited on users
/ 

-- now connect as arup
connect arup/arup

create table t1
(
 col1 number,
 col2 varchar2(1)
)
/
insert into t1 values
(1,’z’) 

/
commit
/
Before you start troubleshooting why a database is slow, you have to first understand that the database itself is never slow or fast—it has a constant speed. The sessions connected to the database, however, slow down when they hit a bump in the road. To resolve a session performance issue, you need to identify the bump and remove it. Fortunately, it’s very easy to do this in most cases. 
The first step to resolving a session performance issue is to ascertain what that database session is doing now. An Oracle Database session is always in one of three states:
  1. Idle. Not doing anything—just waiting to be given some work.
  2. Processing. Doing something useful—running on the CPU.
  3. Waiting. Waiting for something, such as a block to come from disk or a lock to be released.
If a session is waiting to be given work (idle), it’s really not slow at all—it just has nothing to do. If a session is waiting for some resource, such as a block or a lock, it has stopped processing. Until it gets that resource, the session will continue to wait. When it gets that resource, it does some processing and then moves on to the next resource it needs, waits for that to be available, and starts processing . . . and the cycle goes on until the session has nothing else to do. If it waits for resources often, the session will appear slow. But it’s not really slow—it’s just following a pattern of go, stop, go again, stop again, and so on. Your mission is to find and eliminate the “stop” issues in the session.
How difficult is it to get information about what’s causing the session to stop? It’s actually veryeasy: Oracle Database is instrumented to talk about what the database sessions are doing. All you need to do is to listen attentively or, more precisely, look for that information in the right place, and that place is a view called V$SESSION. Everything you need for your analysis is in this view.
To explain how to use the V$SESSION view, I will use a very common scenario—row locking—as an example. To follow along, first set up the previously mentioned tables as described in the online version of this article. Then connect as user ARUP from two different sessions. From the first session, issue the following SQL statement:

update t1
set col2 = 'x' where col1 = 1;

The output will show “1 row updated,” indicating that the row was updated. Do not issue a COMMIT after the statement. By not committing, you will force the session to get and hold a lock on the first row of the T1 table. Now go to the second session and issue the following SQL statement:

update t1
set col2 = 'y' 
where col1 = 1;

This statement will hang. Why? The answer is simple: the first session holds a lock on the row, which causes the second session to hang and the user to complain that the session is slow. To know what the second session is doing, the first thing you need to check is the STATE column in V$SESSION:

select sid, state
from v$session
where username = 'ARUP'; 

SID   STATE
————  ——————————————————
3346  WAITING
2832  WAITED KNOWN TIME

Study the output carefully. Session 3346 (in the SID column) indicates that it is waiting for something—and therefore not working. That should be your first clue that the session is experiencing one of those performance bumps in the road. But before you can determine what the session is waiting for, let’s study the state of session 2832 in the output, which shows that it waited for some known amount of time earlier. The important point is that session 2832 is not waiting for anything right now, meaning that it’s working productively.
Next, let’s see what the second session (3346) is waiting for. That information is readily available in the EVENT column in the same V$SESSION view. The EVENT column not only shows an event a session is waiting for currently, but also shows an event a session has waited for earlier. The query against V$SESSION in Listing 1 displays information from the EVENT column for both sessions.
Code Listing 1: Query for displaying sessions, session state, and events

select sid, state, event
from v$session
where username = 'ARUP'; 

SID   STATE              EVENT
————— —————————————————  ————————————————————————————
2832  WAITED KNOWN TIME  SQL*Net message from client
3346  WAITING            enq: TX - row lock contention

The output in Listing 1 shows that session 3346 is waiting right now for an event: “enq: TX – row lock contention”—short for “enqueue for transaction-level lock on row” or, in plain English, a row-level lock. The session is waiting because it wants to lock one or more rows, but another session has already placed locks on the row or rows. Unless that other session commits or rolls back its transaction, session 3346 will not get the lock it needs and will have no choice but to wait. On the other hand, the state of session 2832, “WAITED KNOWN TIME,” means that it is working—not waiting—right now. It was, however, waiting earlier for an event called “SQL*Net message from client” (I will discuss this specific event later). There is one very important lesson in these results: you cannot look at the EVENT column alone to find out what the session is waiting for. You must look at the STATE column first to determine whether the session is waiting or working and then inspect the EVENT column.
After you determine that a session is waiting for something, the next thing you need to find out is how long the session has been waiting. A very long wait usually indicates some sort of bottleneck. Where can you get information on the length of the waiting period? The answer is right there in the V$SESSION view, in the SECONDS_IN_WAIT column.
Getting the amount of time a session has been waiting makes sense for sessions that are waiting right now, but what about the sessions that are working now? Recall that the EVENT column shows not only the event a session is experiencing now but also the last wait event the session has experienced. Another column—WAIT_TIME—in the same V$SESSION view shows how long that wait lasted. (Note that WAIT_TIME is shown in centiseconds [hundredths of a second].)
Now that you know how to get information on the sessions waiting and working, let’s put all the information together in a single query, shown in Listing 2. It clearly shows the state of the sessions: whether they are working or waiting; if they are working, what they were waiting for earlier and for how long; and if they are waiting, what for and for how long.
Code Listing 2: Query for displaying sessions, session state, and wait details

col "Description" format a50
select sid,
        decode(state, 'WAITING','Waiting',
                'Working') state,
        decode(state,
                'WAITING',
                'So far '||seconds_in_wait,
                'Last waited '||
                wait_time/100)||
        ' secs for '||event
        "Description"
from v$session
where username = 'ARUP';

Output:

SID   STATE       Description
————— ——————————  ———————————————————————————————————————————————————————
2832  Working     Last waited 2029 secs for SQL*Net message from client
3346  Waiting     So far 743 secs for enq: TX - row lock contention
4208  Waiting     So far 5498 secs for SQL*Net message from client

Idle Event

Note the details of session 4208 in Listing 2; it’s currently waiting 5,498 seconds for a “SQL*Net message from client” event. Recall from the previous section that an Oracle Database session can be in one of the three states: working, waiting for a resource, or waiting for work. But how can a session determine whether it is idle? It will expect to be given work by clients via SQL*Net, but there is no way for it to know in advance if any work is coming from the clients. All it can do is wait for some instruction coming through SQL*Net. Until then, it will have nothing else to do but eagerly stare at the SQL*Net interface, and this condition is reported as “SQL*Net message from client” in the V$SESSION view’s EVENT column, which is practically the same thing as just being idle.
You can disregard another EVENT column value, “rdbms ipc message,” because it is an event status for sessions that are idle. Note that an idle session does not show IDLE as the STATE column value; it still shows “Waiting.” You have to check the EVENT column to determine whether the session is truly idle.
You may be tempted to modify the query in Listing 2 to filter sessions that include the “SQL*Net message from client” and “rdbms ipc message” idle events. Although you can do that, I highly discourage doing that, for multiple reasons. First, not all instances of the “SQL*Net message from client” event indicate that the session is idle. Consider the possibility that the network might be truly slow, in which case the session will also wait for these events. Remember, the session doesn’t have the ability to determine whether the client is truly idle or is sending instructions that are slow or stuck in the network. All it can do is wait, and it will wait with the “SQL*Net message from client” event. Second, idle events may provide some clues to Oracle Support about what else is going on inside a session. So I recommend displaying these “idle” EVENT values.

Diagnosis of Locking

The output of Listing 2 provides enough information to enable you to make a diagnosis about the performance of these three sessions. Session 4208 is idle, so any complaints that session 4208 is slow just aren’t related to the database. Any performance issues related to this session could be related to a bug in the code that’s going through an infinite loop or high CPU consumption on the application server. You can redirect the performance troubleshooting focus toward the application client.
The story of session 3346 is different. This session is truly a bottleneck to the application. Now that you know why this session appears slow—it is waiting for a row lock—the next logical question is which session holds that lock. The answer is also found in—I hope you guessed it—the V$SESSION view, in, more specifically, the BLOCKING_SESSION column. (Note that in an Oracle Real Application Clusters [Oracle RAC] environment, the blocking session may exist in a different instance. In such a case, the blocking instance is displayed in the V$SESSION view’s BLOCKING_INSTANCE column.)
You can find out the blocking session and instance by issuing the following SQL statement:

select 
  blocking_session B_SID,
  blocking_instance B_Inst
from v$session
where sid = 3346;

B_SID   B_INST
——————  ———————
 2832      1

The output shows clearly that SID 2832 is holding the lock that SID 3346 is waiting for. Now you can follow a cause/effect relationship between the session in which an update to a row is being blocked and the session that holds the lock on that row.
You can find the specific row that is locked by first finding the table containing that row. To find that table, use the same V$SESSION view; in this case, the information is in the ROW_WAIT_OBJ# column, which shows the object number of the table whose row is being locked. You can then get the name of the table from the DBA_OBJECTS view, using this object number, as shown in Listing 3.
Code Listing 3: Getting row lock information

select row_wait_obj#,
       row_wait_file#,
       row_wait_block#,
       row_wait_row#
from v$session 
where sid = 3346;

ROW_WAIT_OBJ#  ROW_WAIT_FILE#  ROW_WAIT_BLOCK#  ROW_WAIT_ROW#
—————————————  ——————————————  ———————————————— ——————————————
241876         1024            2307623          0

To get the object information:

select owner, object_type, object_name, data_object_id
from dba_objects
where object_id = 241876;

OWNER  OBJECT_TYPE  OBJECT_NAME   DATA_OBJECT_ID
—————  ———————————— ————————————  ——————————————
ARUP   TABLE        T1                    241877

The output shows that some row in the T1 table is the point of the row lock contention. But which specific row is locked? That data is available in three V$SESSION view columns—ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, and ROW_WAIT_ROW#—which show the relative file ID, the block ID in that file, and the row’s slot number inside that block, respectively, for that specific row. Using this information, you can identify the ROWID of the row. The ROWID, the physical address of every row in an Oracle Database instance, can be used to uniquely identify a row.
Listing 4 shows a SQL script that enables you to select the specific blocking row from the table with the information gathered so far. Save this script in a file named rowinfo.sql. The script expects the input in the following order: owner, table name, object#, file#, block#, and row#. You can call this script and pass all the requested parameters by copying and pasting the corresponding output from Listing 3.
Code Listing 4: Finding the row information

REM Filename: rowinfo.sql
REM This shows the row from the table when the
REM components of ROWID are passed. Pass the
REM following in this exact order
REM  1. owner 
REM  2. table name 
REM  3. data_object_id
REM  4. relative file ID 
REM  5. block ID
REM  6. row Number 
REM
select *
from &1..&2
where rowid =
        dbms_rowid.rowid_create (
                rowid_type      =>  1, 
                object_number   => &3,
                relative_fno    => &4,
                block_number    => &5,
                row_number      => &6
        )
/

SQL> @rowinfo ARUP T1 241877 1024 2307623 0

COL1  C
————— —
  1   x

The output in Listing 4 shows the specific row on which a lock is being requested but that is locked by another session. So far you have identified not only the source session of the locking but the specific row being locked as well.
Is it possible that the session holding the lock (SID 2832) is somehow disconnected from the client? That can occur in connection pools or when users access the database with thick-client tools such as Oracle SQL Developer. After you identify the session holding the lock, you may want to wait until it commits or rolls back the transaction. Either action releases the lock.
In the case of a dead connection, you may alternatively decide to kill the session, which will force a rollback releasing the locks held by the blocking session and enabling the waiting sessions to continue. Occasionally the problem can be pretty simple: for instance, someone issued an UPDATE statement from a thick-client tool but forgot to commit and thus caused every session to wait for those updated rows. Identifying that blocking session enables you to send a gentle reminder to rectify that situation immediately.

More on the Session

In many troubleshooting situations, just knowing the SID of each session is not enough. You may need to know other details, such as the client machine the session is connecting from, the user (of both the database and the operating system), and the service name. All of this information is also readily available in the same V$SESSION view you have been using. Let’s briefly examine the columns that provide that information, by running the script shown in Listing 5.
Code Listing 5: Sessions from a specific user

select SID, osuser, machine, terminal, service_name, 
       logon_time, last_call_et
from v$session
where username = 'ARUP'; 

SID   OSUSER  MACHINE   TERMINAL  SERVICE_NAME  LOGON_TIME LAST_CALL_ET
————— ——————  ———————   ————————  ————————————  —————————— ————————————
3346  oradb   prodb1    pts/5     SYS$USERS     05-FEB-12          6848
2832  oradb   prodb1    pts/6     SERV1         05-FEB-12          7616
4408  ANANDA  ANLAP     ANLAP     ADHOC         05-FEB-12             0

OSUSER. The operating system user as which the client is connected. The output indicates that session 4408 is connected from the ANLAP machine, where a Windows user, ANANDA, has logged in.
MACHINE. The name of the machine where the client is running. This could be the database server itself. For two of the sessions, the machine name shows up as “prodb1.” Session 4408 runs on a different machine—ANLAP—presumably a laptop.
TERMINAL. If the session is connected from a UNIX server, this is the terminal where it runs.
LOGON_TIME. This shows when the session was first connected to the Oracle Database instance.
Using the columns shown in Listing 5, you can get very detailed information on a user’s sessions.
Suppose you receive a complaint that the applications running on the application server named appsvr1 are experiencing performance issues. Listing 6 shows a query against the V$SESSION view—including columns you’ve used in previous queries in this article—for the sessions connected from that machine and the output.
Code Listing 6: Session waits for a specific machine

col username format a5
col program format a10
col state format a10
col last_call_et head 'Called|secs ago' format 999999
col seconds_in_wait head 'Waiting|for secs' format 999999
col event format a50
select sid, username, program,
        decode(state, 'WAITING', 'Waiting',
                'Working') state,
last_call_et, seconds_in_wait, event
from v$session
where machine = 'appsvr1'
/
                                       Called      Waiting
SID   USERNAME  PROGRAM       STATE    secs ago    for secs   EVENT 
————— ———————   ———————————   ———————  —————————   ————————   ——————————————————
2832  ARUP      sqlplus.exe   Waiting       152         151   SQL*Net message 
                                                              from client
3089  ARUP      sqlplus.exe   Waiting       146         146   enq: TX - row lock 
                                                              contention
3346  ARUP      sqlplus.exe   Working        18          49   SQL*Net message 
                                                              from client

From the output, you can easily see that three sessions are connected from the appsvr1 application server. All of them are running SQL*Plus (as shown in the PROGRAM column). SID 3346 is the only one that is working (indicated by “Working” in the STATE column). Because it’s working, the EVENT column shows the last time the session waited. The wait time in this case is meaningless, because the session is not waiting but actually working. The “Called secs ago” column (representing the “last_call_et” column in V$SESSION) displays 18, which means that the session made a SQL call 18 seconds ago.
The other sessions are waiting. SID 3089 is waiting for a row lock. From the output, you can see that the session has been waiting for 146 seconds and that it also made its last SQL call 146 seconds ago. This indicates that the session has been waiting for that particular lock ever since it made that SQL call.
Finally, session 2832 is also waiting; in this case, it is waiting with a “SQL*Net message from client” event, which means it is idle, waiting to be given some work. The session issued its last SQL statement 152 seconds ago and has been idle for 151 seconds.
Armed with this information, you can diagnose performance issues very accurately. You can tell the complaining user that of the three sessions connected from the appsvr1 application server, one session is idle, one is working, and one is waiting for a lock. The user is probably referring to the slowness of this last session. Now you know the reason and how you can rectify it.

Getting the SQL

Another key piece of performance tuning information is the SQL statement a session is executing, which will provide more insights into the workings of the session. The same V$SESSION view also shows the SQL statement information. The SQL_ID column in the V$SESSION view shows the ID of the last SQL statement executed. You can get the text of that SQL statement from the V$SQL view, using the SQL_ID value. Here is an example of how I have identified the SQL statement executed by the session that appears slow to the user.

select sql_id
from v$session
where sid = 3089;

SQL_ID
—————————————————
g0uubmuvk4uax

set long 99999
select sql_fulltext
from v$sql
where sql_id = 'g0uubmuvk4uax';
SQL_FULLTEXT
————————————————————————————————————————
update t1 set col2 = 'y' where col1 = 1

Data Access Issues

I have used row-level locking as the cause of a slowdown in this article. Although locking-related contention is a very common cause, it is not the only cause of performance problems. Another major cause of contention is disk I/O. When a session retrieves data from the database data files on disk to the buffer cache, it has to wait until the disk sends the data. This wait shows up for that session as “db file sequential read” (for index scans) or “db file scattered read” (for full-table scans) in the EVENT column, as shown below:

select event
from v$session
where sid = 3011;

EVENT
—————————————————————————
db file sequential read

When you see this event, you know that the session is waiting for I/O from the disk to complete. To make the session go faster, you have to reduce that waiting period. There are several ways to reduce the wait:
  1. Reduce the number of blocks retrieved by the SQL statement. Examine the SQL statement to see if it is doing a full-table scan when it should be using an index, if it is using a wrong index, or if it can be rewritten to reduce the amount of data it retrieves.
  2. Place the tables used in the SQL statement on a faster part of the disk.
  3. Consider increasing the buffer cache to see if the expanded size will accommodate the additional blocks, therefore reducing the I/O and the wait.
  4. Tune the I/O subsystem to return data faster.

Next Steps

There are other options as well, but the preceding ones are the most common remediation techniques. The exact activity you undertake depends on your specific situation, but the first technique—reducing the number of blocks retrieved by a SQL statement—almost always works. 

When you think about tuning to reduce the number of blocks, you can look at the SQL statement to see which table is being selected from. But what if you see two or more tables in the statement? How do you determine which table is causing the wait?
To find the table causing a wait, you will again use the V$SESSION view. The view’s P1 and P2 columns provide information about the segment the session is waiting for. Listing 7 shows a query of P1 and P2, and the output.
Code Listing 7: Checking data access waits

select SID, state, event, p1, p2
from v$session
where username = 'ARUP'; 

SID  STATE     EVENT                   P1 P2
———— ———————   ——————————————————————— —— ————
2201 WAITING   db file sequential read  5 3011

The P1 column shows the file ID, and the P2 column shows the block ID. From that information in the result in Listing 7, you can get the segment name from the extent information in DBA_EXTENTS, as shown below:

select owner, segment_name
from dba_extents
where file_id = 5
and 3011 between block_id 
and block_id + blocks;

OWNER  SEGMENT_NAME
—————— —————————————
ARUP   T1

This shows that the T1 table, owned by ARUP, is being selected from by the disk in the session. You should direct your attention to this table for tuning. You can move the table to a high-speed disk for faster I/O, or, alternatively, you can focus on making I/O in this table faster by making changes that affect this table, such as creating new indexes, creating materialized views, or building a result cache.

Conclusion

In summary, this article presented the following steps for starting a successful performance tuning session:
  1. Check whether the session is working or waiting. If the latter, determine what it is waiting for and how long it has been waiting.
  2. Compare the waiting period of the session with how long ago it issued a SQL call.
  3. If the cause of the wait is a lock contention, find the session holding the lock and get the details of the session. (If the session holding the lock is an orphan session, you may want to kill it to release the lock.)
  4. Find the SQL statement the session is executing.
  5. If the session is waiting for I/O, find out which segment (table, materialized view, index, and so on) the I/O is waiting for.
The techniques presented in this article will help you resolve about 20 percent of the performance issues you encounter as a DBA. Oracle Database is instrumented to provide information on its inner workings so that you can zero in on the exact cause of an issue—all you have to do is listen.
I sincerely hope that this article has helped you realize how simple it is to diagnose some common but seemingly thorny performance issues in Oracle Database by identifying the right information sources. Happy tuning!