Showing posts with label Sessions. Show all posts
Showing posts with label Sessions. Show all posts

Wednesday, January 31, 2024

How come I cannot logon to my instance as sysdba, when the ORACLE_SID variable is set correctly?

Here's a reminder if you use a symbolic link for your ORACLE_HOME variable:

You will not be able to attach to your instance using OS authentication, like under the following circumstances:
echo $ORACLE_SID
testdb01
echo $ORACLE_HOME=/orasw/oracle/product/current
ls -la /orasw/oracle/product/current
lrwxrwxrwx 1 oracle dba 12 Jan 31 08:34 /orasw/oracle/product/current -> 19.21
ls -la 
sqlplus / as sysdba
The above statement will not be able to connect to your instance.

You can, however, connect to the instance by going through the listener instead:
sqlplus sys@testdb01 as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Jan 31 08:38:42 2024
Version 19.21.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Enter password:

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.21.0.0.0

SYS@testdb01>SQL>show user
USER is "SYS"
So in order to create a bequeath session, you need an ORACLE_HOME variable that does not use symbolic links.

See this post about IPC and bequeath sessions for more details.

Thursday, September 1, 2022

What is the missing privilege when receiving ORA-01031: insufficient privileges when switching container?

You need to grant the SET CONTAINER system privilege to a common user, in order for the user to be able to switch container.

Eksample: you have a common user used for auditing, C##AUDITADMIN:
CREATE USER c##auditadmin IDENTIFIED BY  CONTAINER=ALL;
GRANT AUDIT_ADMIN TO c##auditadmin CONTAINER=ALL;
GRANT SELECT ANY TABLE TO c##auditadmin CONTAINER=ALL;
GRANT CREATE SESSION TO c##auditadmin CONTAINER=ALL;
You log in with your user to the root container:
sqlplus c##auditadmin@cdb
Enter password:

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

C##AUDITADMIN@cdb SQL> alter session set container=pdb1;
ERROR:
ORA-01031: insufficient privileges
To grant the required privilege, login as sysdba:
sqlplus / as sysdba

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0
Grant the SET CONTAINER privilege:
SYS@cdb SQL> grant set container to c##auditadmin container=all;

Grant succeeded.
Connect with C##AUDITADMIN again, and switch to the PDB1 container within your session:
sqlplus c##auditadmin@cdb

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

C##AUDITADMIN@cdb SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT
C##AUDITADMIN@cdb SQL> alter session set container=pdb1;

Session altered.

C##AUDITADMIN@cdb SQL> show con_name

CON_NAME
------------------------------
PDB1

Wednesday, December 22, 2021

What is the difference between "force parallel" and "enable parallel" used in the "alter session" statement in Oracle?

What is the difference between these two statements?
ALTER SESSION ENABLE PARALLEL DML | DDL | QUERY;
and
ALTER SESSION FORCE PARALLEL DDL | DML | QUERY;
Answer:

The difference here lays in the details: the ENABLE statement merely enables parallelization using a concrete parallel directive or parallel hint. If this is not specified, Oracle will execute the statements sequenctually. The FORCE statement will parallelize everything it can with the default DOP (degree of parallelism), without you having to state anyting about this in your DML | DDL or query statements.

If the default DOP isn't good enough for you (for example during an index rebuild), you can force your session to use a DOP higher than the default, like this:
ALTER SESSION FORCE PARALLEL DDL | DML | QUERY PARALLEL 32;
This will override any other DOP in the same session and use 32 parallel workers.

Alter session in 19c is documentet here
The concept of forcing/enabling parallelization is explained here

Wednesday, November 3, 2021

An Oracle procedure that allow users to kill their own sessions

First, create a view that lets the users check their own sessions:
connect / as sysdba

create or replace view my_sessions as
select username,sid,serial#,osuser,status,program,machine
from v$session
where username=SYS_CONTEXT('userenv','CURRENT_SCHEMA');
Create a public synonym, and grant select to public:
create public synonym my_sessions for my_sessions;
grant select on my_sessions to public;
To get the procedure to compile in the SYSTEM schema, it is required to grant the "alter system" privilege directly to the user - having the same privilege through a role won't do.
grant alter system to system;
grant select on v_$session to system;
Log in as system, and create the procedure:
CREATE OR REPLACE PROCEDURE KILL_SESSION(PN_SID NUMBER,PN_SERIAL NUMBER) AUTHID DEFINER
AS
LV_USER VARCHAR2(30);
EXE_USER VARCHAR2(30);
BEGIN
    SELECT S.USERNAME INTO LV_USER 
    FROM V$SESSION S, USER_USERS U 
    WHERE S.SID    = PN_SID 
    AND S.SERIAL#  = PN_SERIAL
    AND S.USERNAME = S.USERNAME;

    SELECT USERNAME INTO EXE_USER
    FROM V$SESSION 
    WHERE AUDSID=SYS_CONTEXT('userenv','SESSIONID');

 IF EXE_USER = LV_USER THEN
    EXECUTE IMMEDIATE 'alter system kill session '''||PN_SID||','||PN_SERIAL||'''';
    dbms_output.put_line('Session ' || PN_SID || ',' || PN_SERIAL || ' killed.');
ELSE
    RAISE_APPLICATION_ERROR(-20000,'Only your own sessions may be killed.');
END IF;
END;
/  
Create a synonym for the procedure and give everyone execute privileges on it:
CREATE PUBLIC SYNONYM KILL_SESSION FOR KILL_SESSION;
GRANT EXECUTE ON KILL_SESSION TO PUBLIC;
Now the users have a way to check their own sessions, and to terminate them if they chose to do so:
connect scott
select * from my_session;

USERNAME                    SID    SERIAL# OSUSER               STATUS               PROGRAM                                          MACHINE
-------------------- ---------- ---------- -------------------- -------------------- ------------------------------------------------ ----------------------------------------------------------------
SCOTT                        1152       9510 oracle               INACTIVE             sqlplus@myserver.mydomain.com (TNS V1- myserver.mydomain.com
SCOTT                        1726      31531 oracle               ACTIVE               sqlplus@myserver.mydomain.com (TNS V1- myserver.mydomain.com
Kill a session:
scott@mydb>SQL>exec kill_session(1152,9510);
Afterwards, the view will change to show session 1152 to be in status KILLED:
USERNAME                    SID    SERIAL# OSUSER               STATUS               PROGRAM                                          MACHINE
-------------------- ---------- ---------- -------------------- -------------------- ------------------------------------------------ ----------------------------------------------------------------
SCOTT                        1152       9510 oracle               KILLED             sqlplus@myserver.mydomain.com (TNS V1- myserver.mydomain.com
SCOTT                        1726      31531 oracle               ACTIVE               sqlplus@myserver.mydomain.com (TNS V1- myserver.mydomain.com

Thursday, March 7, 2019

How to use dbms_session to set client_identifier in your session



Logged in as user scott, I set the following in my session:
EXEC DBMS_SESSION.SET_IDENTIFIER (client_id=>'vegardk');

Verify that your session info is set:
SELECT SYS_CONTEXT( 'USERENV', 'CLIENT_IDENTIFIER' ) "client identifier", SYS_CONTEXT( 'USERENV', 'CURRENT_USER' ) "current user" 
FROM DUAL;

client identifier current user
vegardk SCOTT

The same information can be found in v$session, columnn CLIENT_IDENTIFIER.

There is also another column in v$session called CLIENT_INFO.
A value for this column can be generated by calling a different procedure, dbms_application_info.set_client_info.

For example:
exec dbms_application_info.set_client_info('Execute summary');
Check v$session:
SELECT USERNAME,CLIENT_IDENTIFIER,CLIENT_INFO
FROM V$SESSION 
WHERE USERNAME='SCOTT';

Result:
USERNAME CLIENT_IDENTIFIER CLIENT_INFO
SCOTT vegardk Execute summary

A good way to pick up up any relevant session information already set is to use NVL:
SELECT NVL(SYS_CONTEXT( 'USERENV', 'CLIENT_IDENTIFIER' ), SYS_CONTEXT( 'USERENV', 'CURRENT_USER' )) 
FROM DUAL;
If client_identifier is set, we pick up that value. If not, we use the current_user, which is always set.
This could also be used as a default value for a column definition:
  CREATE TABLE T1 (
  ...
  LAST_CHANGED_BY     VARCHAR2(30 CHAR)         DEFAULT NVL(SYS_CONTEXT( 'USERENV', 'CLIENT_IDENTIFIER' ), SYS_CONTEXT( 'USERENV', 'CURRENT_USER' )) NULL
 );

Wednesday, March 15, 2017

How to find wait information about a session


Yesterday, I had started a script with two long-running queries before I my shift ended, and it was finished when I got back, as expected. The session was still connected to the database and waiting for some time. I was curious how long time the SQL took, and I forgot to set timing on in sqlplus.

SELECT 
    S.SID,
    S.SERIAL#,
    S.STATUS "status",
    S.LOGON_TIME "logon time",
    S.PREV_EXEC_START "last op started",
    Q.LAST_ACTIVE_TIME "last op ended", 
    S.STATE "state",
    S.EVENT "event",
    ROUND((S.WAIT_TIME_MICRO/1000000)/60/60,1) "total wait hrs",
    DECODE(S.TIME_REMAINING_MICRO,'-1', 'indefinite', '0','Wait timed out',NULL,'session not waiting') "remaining wait time", 
    DECODE(S.TIME_SINCE_LAST_WAIT_MICRO, '0','Still waiting') "current status"
FROM V$SESSION S  JOIN V$SQL Q 
ON (S.SQL_ID = Q.SQL_ID)
WHERE SID=1758;

The output below shows that my session was established at 14:33, and the last operation ended at 19:20. In other words, it took approximately 5 hours for the two statements in my script to finish:

SID SERIAL# status logon time last op started last op ended state event total wait hrs remaining wait time current status
1758
35360
INACTIVE 14.03.2017 14:33:42 14.03.2017 19:10:31 14.03.2017 19:20:52 WAITING SQL*Net message from client
13,2
indefinite Still waiting


Note that v$session column "seconds_in_wait" has been deprecated. You should use "wait_time_micro" instead.

Thursday, January 12, 2017

How to solve ORA-02391 exceeded simultaneous SESSIONS_PER_USER limit

The error definition:

//  *Cause: An attempt was made to exceed the maximum number of
//          concurrent sessions allowed by the SESSION_PER_USER clause
//          of the user profile.
//  *Action: End one or more concurrent sessions or ask the database
//           administrator to increase the SESSION_PER_USER limit of
//           the user profile.

You need to adjust the SESSIONS_PER_USER of the profile the user is assigned to.
alter profile general_users LIMIT SESSIONS_PER_USER <num> | default | unlimited;

num = a fixed number of sessions that is the upper bound for the number of concurrent session the user can create
Default = the user is subject to the limits on those resources defined by the DEFAULT profile
unlimited = the user assigned this profile can use an unlimited amount of this resource

Tuesday, December 20, 2016

Will interrupting a "split partition"-command cause any harm to your database?

Will interrupting a "alter table split partition"-command cause any harm to your database?

No, it will not. It is safe to kill the session. Oracle will be able to recover and the table would be left in its original state, prior to time when the "alter table split partition" command was executed.

I was recently in contact with Oracle support regarding such a case. My goal was to split a sub-partition, in order to accommodate rows for years 2017 to 2020, but there was way too much concurrent activities in the database to complete the "alter table split partition"-command.
The database was almost completely non-responsive and there was pressure to finish within a certain time frame.

The supporting engineer confirmed that there would be some rollback activities in the wake of this command, how much depended on the activity level in the database during the time when the DDL was executing.

He added the following explanation to how Oracle handles the split internally:

As for kill the split partition, the way it works internally is to create temporary segments for the 2 new partitions it is splitting into, and when the operation is complete, these new temporary segments are attached to the original table and become the new partitions. So the result of this is that it's perfectly safe to terminate the split partition, and it simply stops its work, drops the temporary segments, and you are left with the original table in-tact, so there will be no ill-effects of this.

Sunday, December 18, 2016

How to create a common and a local user in a 12c multitenant database

In a multitenant container database, there are two types of users:

* Common users, who are known in both the root containers and in all the pluggable database containers
* Local users, who are only known in a single pluggable database container

Common users can, if granted the necessary privileges, perform administrative tasks across all the PDBs in multitenant database.
They can also perform tasks specific to the container database, also called the ROOT container.

To create a common user, make sure you are connected to the ROOT container

On my client, my tnsnames.ora entry looks as follows:
# container database
CDB =
   (DESCRIPTION =
     (ADDRESS = (PROTOCOL = TCP)(HOST = myhost.mydomain.no)(PORT = 1531))
     (CONNECT_DATA =
       (SERVER = DEDICATED)
       (SERVICE_NAME = "container#db01")
     )
   )


Since my client is a windows pc, I start sqlplus from the start menu, and connect as system@cdb and enter the password.
My default container will be CDB$ROOT, which is what you need to create a common user:
show con_name

CON_NAME
------------------------------
CDB$ROOT


Create the common user:
create user C##DBAMASTER
identified by ****
default tablespace USERS
temporary tablespace TEMP
quota unlimited on USERS
container=all;

SQL> user C##DBAMASTER created.

Note the new rules for creating common users in a CDB database:
In Oracle Database 12c Release 1 (12.1.0.1), the name of a common user must begin with C## or c##

Verify that the common user was created:
select USERNAME,CREATED,LAST_LOGIN,COMMON
from dba_USERS
where trunc(created) = trunc(sysdate)

USERNAME             CREATED   LAST_LOGIN                               COM
-------------------- --------- ---------------------------------------- ---
C##DBAMASTER         18-DEC-16 18-DEC-16 03.16.16.000000000 PM +01:00   YES


Give the common user the right to create a session, to switch between all containers in the CDB and the right to create and drop users in all the containers in the CDB:
grant connect to C##DBAMASTER;
grant set container to C##DBAMASTER container=all;
grant create user to C##DBAMASTER container=all;
grant drop user to C##DBAMASTER container=all;

SQL> Grant succeeded.

Connect to ROOT container as the new common user:
connect C##DBAMASTER/***@cdb
Connected.
show user
USER is "C##DBAMASTER"
Switch container:
alter session set container=vpdb01;

SQL> Session altered.
Create a new local user in the current container:
create user "1Z0061"
identified by ****
default tablespace users
quota unlimited on users
temporary tablespace TEMP
container=current;

SQL> User created.

Note that without the "container=all" privilege, the new common user C##DBAMASTER cannot connect directly to the vpdb01 pluggable database

Here is what happened:
SQL> connect C##DBAMASTER/****@vpdb01
ERROR:
ORA-01045: user C##DBAMASTER lacks CREATE SESSION privilege; logon denied


Warning: You are no longer connected to ORACLE.
SQL> connect system/*****@vpdb01
Connected.
SQL> show con_name

CON_NAME
------------------------------
VPDB01
SQL> grant create session to C##DBAMASTER container=current;

Grant succeeded.

SQL> connect C##DBAMASTER/****@vpdb01
Connected.
SQL> show con_name

CON_NAME
------------------------------
VPDB01

This means that these two privileges are distinctly different:
grant create session to C##DBAADMIN container=all;
vs
grant set container to C#DBAADMIN container=all;

Friday, January 23, 2015

What is the difference between a BEQUEATH connection and an IPC connection?

A bequeath connection
  • runs on your local host
  • bypasses the listener
  • the protocol creates the server process for you directly

    An IPC (Inter-Process Communication) connection
  • will use the native protocol on each OS, but uses the generic term "IPC" for all of them
  • can only be used when the Client and Server reside on the same host
  • can only be used by having the Client connect through the Oracle Listener
  • the Database Listener must be configured to listen on an IPC endpoint
  • the listener spawns the server process for you

    Example setup:
    Listener.ora
     LISTENER =
       (DESCRIPTION_LIST =
         (DESCRIPTION =
           (ADDRESS = (PROTOCOL = TCP)(HOST = myserver)(PORT = 1521))
           (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
         )
       )
    

    tnsnames.ora:
    proddb01_ipc =
       (DESCRIPTION =
         (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
         (CONNECT_DATA =
           (SERVER = DEDICATED)
           (SERVICE_NAME = proddb01)
         )
       )
    
    Connect to your database locally:
    sqlplus /nolog
    SQL*Plus: Release 11.2.0.4.0. Production on Thu Jan 22 15:35:44 2015
    
    Copyright (c) 1982,2013, Oracle. All rights reserved.
    
    SQL> connect scott/tiger
    Connected.
    
    From another window, create another session:
    sqlplus /nolog
    SQL*Plus: Release 11.2.0.4.0. Production on Thu Jan 22 15:35:44 2015
    
    Copyright (c) 1982,2013, Oracle. All rights reserved.
    
    SQL> connect scott/tiger@proddb01_ipc
    Connected.
    

    Check the connections and their types:
    SELECT S.SID, S.OSUSER,S.PROGRAM,S.USERNAME,S.MACHINE, SCI.NETWORK_SERVICE_BANNER,S.LOGON_TIME,S.STATUS
     FROM V$SESSION S INNER JOIN V$SESSION_CONNECT_INFO SCI
     ON S.SID = SCI.SID
     WHERE S.USERNAME = UPPER('scott')
     AND SCI.NETWORK_SERVICE_BANNER LIKE '%IPC%'
     OR  SCI.NETWORK_SERVICE_BANNER LIKE INITCAP('%BEQ%')
     AND S.TYPE <> 'BACKGROUND'
     ORDER BY LOGON_TIME;
    

    And here is the output. Notice how the first session (.. / as sysdba) results in a Bequeath session, while the other one ( ...@proddb_ipc) results in a session using IPC:

    SIDOSUSERPROGRAMUSERNAMEMACHINENETWORK_SERVICE_BANNERLOGON_TIMESTATUS
    9
    oraclesqlplus@myserver.mydomain.com (TNS V1-V3)SCOTTmyserver.mydomain.comOracle Bequeath NT Protocol Adapter for Linux: Version 11.2.0.4.0 - Production22.01.2015 15:35:49INACTIVE
    1160
    oraclesqlplus@myserver.mydomain.com (TNS V1-V3)SCOTTmyserver.mydomain.comUnix Domain Socket IPC NT Protocol Adaptor for Linux: Version 11.2.0.4.0 - Production22.01.2015 15:40:44INACTIVE















  • Tuesday, August 26, 2014

    How to find the SID, serial# and their operating system process ID from the database

    A simple statement to find the SID, serial# and their operating system process ID from the database:

    SET LINES 300 PAGES 300
    SET TRIMSPOOL ON
    SPOOL SQL
    COL "Os pid" FORMAT A10
    COL MACHINE  FORMAT A30
    COL "SQL Text" FORMAT A100 WRA
    COL PROGRAM  FORMAT A20
    COL USERNAME FORMAT A12
    
    SELECT
      S.SID,
      S.SERIAL#,
      S.USERNAME,
      S.STATUS,
      P.SPID "Os pid",
      S.MACHINE,
      CONCAT(SUBSTR(A.SQL_TEXT,1,60), '...(output truncated)')  "SQL text"
    FROM V$SESSION S,
              V$SQLAREA A,
              V$PROCESS P
    WHERE A.ADDRESS = S.SQL_ADDRESS
    AND S.PADDR=P.ADDR
    ORDER BY 1
    /
    
    Example output:
    SID          SERIAL# USERNAME     Os pid     MACHINE          SQL text
    ---------- ---------- ------------ ---------- -------------  ------------------------------------------------------------------------------------
             4          3              6357052    myserver       insert into obj$(owner#,name,namespace,obj#,type#,ctime,mtim...(output truncated)
            18       7035 SYS          21496004   myserver       call DBMS_AQADM_SYS.REGISTER_DRIVER (  )...(output truncated)
           107      62143 SYS          23527460   myserver       SELECT   S.SID,   S.SERIAL#,   S.USERNAME,   P.SPID "Os pid"...(output truncated)
           303      27191 SYS          16777372   myserver       analyze table scott.man_to_stage validate structure cascade o...(output truncated)
           393          1              8716332    myserver       insert into obj$(owner#,name,namespace,obj#,type#,ctime,mtim...(output truncated)
           402       3125 BATCHUSR     18612294   myserver       call mypackage.start_dorg (  )...(output truncated)
           490          1              8257548    myserver       insert into obj$(owner#,name,namespace,obj#,type#,ctime,mtim...(output truncated)
           499      25461 SYS          13762730   myserver       call DBMS_AQADM_SYS.REGISTER_DRIVER (  )...(output truncated)
           503       2635 SYS          11272234   myserver       call DBMS_AQADM_SYS.REGISTER_DRIVER (  )...(output truncated)
           593      12091 BATCHUSR     19726590   myserver       call myprocedure.read_queue (  )...(output truncated)
           600       9193 SYS          21102724   COMP\PC1       select * from dba_locks...(output truncated)
           694      44601 BATCHUSR     20840656   myserver       call mypackage.check_job_consistency(  )...(output truncated)
           696        819 SYS          15269968   myserver       call DBMS_AQADM_SYS.REGISTER_DRIVER (  )...(output truncated)
           700       1135 BATCHUSR     21364890   myserver       DECLARE job BINARY_INTEGER := :job;  next_date TIMESTAMP WIT...(output truncated)
    


    Tuesday, July 15, 2014

    What is the difference between the columns PID and SPID in v$process?

    The PID column is an internal counter that oracle uses for its own processes. It is incremented by one for every new process. Consequently, since every session creates its own server process (also called "shadow process") you will see the number increment by one for each session that connects.

    The documentation for V$PROCESSES states that PID is the "Oracle Process Identifier" which is confusing.
    In most circumstances, the column that you would need is the SPID, which shows the "Operating system process identifier".

    Thursday, March 6, 2014

    How to use v$session_longops to check long running processes

    I am setting NLS_DATE_FORMAT so that the START_TIME and LAST_UPDATE_TIME will be more accurate.

    SET TERMOUT OFF
    ALTER SESSION SET NLS_DATE_FORMAT='DD.MM.YYYY HH24:MI:SS';
    SET TERMOUT ON
    SET LINES 300
    COL "CURRENTLY EXECUTING" FORMAT A35
    COL OSUSER FORMAT A10
    COL MACHINE FORMAT A20
    COL USERNAME FORMAT A20
    COL PROGRAM FORMAT A40
    COL UNITS FORMAT A20
    COL OPNAME FORMAT A10
    COL START_TIME FORMAT A20
    COL LAST_UPDATE_TIME FORMAT A20
    COL SQL_ID FORMAT A15
    SET VERIFY OFF
    SET FEEDBACK OFF
    
    SELECT
        S.SID,
        S.SERIAL#,
        S.OSUSER,
        S.MACHINE,
        S.USERNAME,
        S.PROGRAM,
        S.SQL_ID,
        SUBSTR(Q.SQL_TEXT,1,30) || '...' "CURRENTLY EXECUTING",
        L.OPNAME,
        L.SOFAR,
        L.TOTALWORK,
        L.UNITS,
        L.START_TIME,
        L.LAST_UPDATE_TIME,
        L.TIME_REMAINING "SECONDS LEFT",
        TO_TIMESTAMP(L.LAST_UPDATE_TIME,'DD.MM.YYYY HH24:MI:SS')-TO_TIMESTAMP(L.START_TIME,'DD.MM.YYYY HH24:MI:SS') "RUNNING FOR"
    FROM V$SESSION_LONGOPS L JOIN V$SESSION S ON L.SID = S.SID
                             JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID
    AND   S.SID = &SID
    AND   S.SERIAL#  = L.SERIAL#
    ORDER BY L.LAST_UPDATE_TIME DESC;
    
    EXIT
    

    Result:
    SID SERIAL# OSUSER MACHINE USERNAME PROGRAM SQL_ID CURRENTLY EXECUTING OPNAME SOFAR TOTALWORK UNITS START_TIME LAST_UPDATE_TIME SECONDS LEFT RUNNING FOR
    408 2624 oracle testserver1 SH sqlplus@testserver1 (TNS V1-V3) 3w11rcbvd5a32 UPDATE SALES_Q1_DI_MASTERS SET ... Table Scan 82432 82636 Blocks 06.03.2014 07:35:26 06.03.2014 09:44:22 19 +00 02:08:56.000000

    Thursday, February 13, 2014

    An easy way to find DML locks

    The view DBA_DML_LOCKS is a convenient view to use if you want to identify locks caused by uncommited DML statements.

    Consider the following simple example:

    INSERT INTO FAMILY_TREE
    (PERSON_ID, FULL_NAME, GENDER, CITIZENSHIP, COUNTRY_OF_RESIDENCE)
    VALUES
    (5, 'Arne Kåsa', 'M', 'Norwegian', 'Sweden');

    -- Do not commit --

    Logged in as a privileged user from another session, execute:

    SELECT * FROM DBA_DML_LOCKS WHERE OWNER = 'VEGARDK';

    SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTED LAST_CONVERT BLOCKING_OTHERS
    362 VEGARDK FAMILY_TREE Row-X (SX) None 39 Not Blocking

    COMMIT;

    SELECT * FROM DBA_DML_LOCKS WHERE OWNER = 'VEGARDK';

    No rows returned.

    Friday, January 10, 2014

    How to display session information, followed by a kill-statement

    Often, my customers ask me to kill a runaway session for them, typically this will be in the form "Can you please kill session with session id 170 for us?. It's urgent!"

    Before I do so, I'd like to be one houndred percent certain that I kill the right session.
    To help me in such situations, I execute the script below. It will take one parameter, the sessions SID, and echo back some basic information about what the session is doing. Finally it prints a "kill session" command, which I can choose to execute if it was indeed the right session.

    set verify           off
    set linesize 200
    col "os process"     format a30
    col "os process id"  format a10
    col "osuser"         format a15
    col "schemaname"     format a20
    col "client program" format a20
    col "client name"    format a20
    col "session type"   format a20
    col status           format a10
    col "session type"   format a15
    cle scr
    prompt ===================================================
    prompt This script will print basic information about a
    prompt session.
    prompt
    accept SID prompt 'Pls enter SID of session: '
    prompt ===================================================
    prompt  Information about database session &&SID
    prompt ===================================================
    column host_name new_value v_hostname;
    
    set termout off
    select host_name
    from   v$instance;
    set termout on
    
    select
            p.program "os process",
            p.spid "os process id",
            p.username "osuser",
            s.sid,s.serial# "serial num",
            lower(s.schemaname) "schemaname",
            lower(s.osuser) "client name",
            s.program "client program",
            lower(s.status) "status",
            lower(s.type) "session type"
    from v$process p, v$session s
    where p.program not like 'oracle@v_hostname (%'
    and p.addr = s.paddr
    and p.addr = (select paddr from v$session where sid=&&SID)
    order by s.username asc
    /
    set heading off
    prompt ===================================================
    prompt  Kill statement for session &&SID:
    prompt ===================================================
    select 'alter system kill session ''' || s.sid || ',' || s.serial# || ''';'
    from   v$process p, v$session s
    where  p.program not like 'oracle@v_hostname (%'
    and    p.addr = s.paddr
    and    p.addr = (select paddr from v$session where sid=&&SID)
    order by s.username asc
    /
    
    exit
    

    Tuesday, October 29, 2013

    How to set the current schema in a session

    alter session set current_schema=SCOTT;

    The CURRENT_SCHEMA parameter changes the current schema of the session to the specified schema.
    Subsequent unqualified references to schema objects during the session will resolve to objects in the specified schema.
    The setting persists for the duration of the session or until you issue another ALTER SESSION SET CURRENT_SCHEMA statement.

    This setting offers a convenient way to perform operations on objects in a schema other than that of the current user
    without having to qualify the objects with the schema name.

    This setting changes the current schema, but it does not change the session user or the current user,
    nor does it give the session user any additional system or object privileges for the session.

    Source: Oracle Documentation

    Tuesday, October 22, 2013

    How to generate scripts to move partitions to a new tablespace while updating the indexes

    Probably many ways of doing this, but here is how I generated scripts to move table partitions from one tablespace to another:
    -- Find table partitions with GLOBAL indexes:
    SELECT 'ALTER TABLE ' || TABLE_OWNER || '.' || TABLE_NAME || ' MOVE PARTITION "' || PARTITION_NAME || '" TABLESPACE DATA2 NOCOMPRESS UPDATE GLOBAL INDEXES;'
    FROM    dba_tab_partitions
    WHERE   table_owner         = 'USER1'
    AND     tablespace_name     = 'DATA1'
    AND     subpartition_count  = 0
    AND     table_name IN (
            SELECT  distinct table_name   
            FROM    dba_part_indexes
            WHERE   owner = 'USER1'
            AND     locality = 'GLOBAL'
    )
    ORDER BY table_name DESC;
    
    -- Find table partitions with LOCAL indexes:
    SELECT 'ALTER TABLE ' || TABLE_OWNER || '.' || TABLE_NAME || ' MOVE PARTITION "' || PARTITION_NAME || '" TABLESPACE DATA2 NOCOMPRESS UPDATE INDEXES;'
    FROM    dba_tab_partitions
    WHERE   table_owner         = 'USER1'
    AND     tablespace_name     = 'DATA1'
    AND     subpartition_count  = 0
    AND     table_name IN (
            SELECT  distinct table_name   
            FROM    dba_part_indexes
            WHERE   owner = 'USER1'
            AND     locality = 'LOCAL'
    )
    ORDER BY table_name DESC;
    
    
    -- Find table partitions with no index at all
    SELECT 'ALTER TABLE ' || TABLE_OWNER || '.' || TABLE_NAME || ' MOVE PARTITION "' || PARTITION_NAME || '" TABLESPACE DATA2 NOCOMPRESS;'
    FROM    dba_tab_partitions
    WHERE   table_owner         = 'USER1'
    AND     tablespace_name     = 'DATA1'
    AND     subpartition_count  = 0
    AND     table_name NOT IN (
            SELECT  table_name   
            FROM    dba_part_indexes
            WHERE   owner = 'USER1'
    )
    ORDER BY table_name DESC;
    
    

    Saturday, October 19, 2013

    Some useful session views - short description

    V$SESSION --> displays information about the current session

    V$SESSION_EVENT --> shows all the wait events waited for by the session. Note that it will show the data only if the session is still active in the database

    V$SESSTAT --> shows the resource usage for a session
    Some useful statistics visible in the V$SESSTAT view:
    - physical reads: the number of database blocks retrieved from disk
    - db block changes: the number of database blocks changed in the session
    - bytes sent via SQL*Net to client: the bytes received from the client over the network, which is used to determine the data traffic from the client

    V$ACTIVE_SESSION_HISTORY --> shows historical session information

    DBA_HIST_ACTIVE_SESS_HISTORY --> contains the same data as V$ACTIVE_SESSION_HISTORY, but with less granularity, only every 10th second sampling

    How to name a trace file to find it more easily

    alter session set tracefile_identifier = 'your string for easy recognition here';

    For example:

    alter session set tracefile_identifier = 'data_pump_import_trace.trc';

    If you trace your session now, your file will now be much easier to find in the udump directory (pre 11g) or in the diagnostic_dest/trace directory (11g and onwards)

    How to set a timeout for DDL operations in oracle11g - to avoid "resource busy" error

    ALTER SESSION SET DDL_LOCK_TIMEOUT = 10;

    when a DDL statement in the session does not get the exclusive lock, it will not error out.
    Instead, it will wait for 10 seconds. In that 10 seconds, it continually re-tries the DDL operation until it is successful or the time expires, whichever comes first.

    For exammple, if the following query is executed:


    SQL> alter table sales add (tax_code varchar2(10));

    the statement hangs and does not error out.

    Arup Nanda puts it as
    somewhat like a telephone programmed to re-try a busy number

    To set it database-wide:

    ALTER SYSTEM SET DDL_LOCK_TIMEOUT = 10;