Tuesday, June 11, 2013

Derived Objects Replication Using Oracle Goldengate

As usual with questions, 
  1. I have my source and target schema names different, do we need to check something during replication
  2. Should i worry about schema name being referenced while issuing DDL at source

Yes its about derived objects and its impact during replication using Oracle Goldengate. So what do you mean by derived objects, 















Lets see how does the inclusion of schema name impact Oracle Goldengate replication. 

Details of setup 
Source DB        - OMS
Schema Name - hari
Target DB         - OGG
Schema Name - puthranv

Before getting into Derive Objects Replication, Lets start with 

  1. OGG process setup
  2. DML Replication
  3. DDL Replication and then 
  4. Derived Object Replication

At Source - Basic info 
SQL> 
SQL> 
SQL> show user
USER is "HARI"
SQL> 
SQL>
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

SQL>
SQL> select name,log_mode from v$database;

NAME      LOG_MODE                                                              
--------- ------------                                                          
OMS  ARCHIVELOG                                                            

SQL> 


Creating a simple table

SQL> 
SQL> REM-'SOURCE'
SQL> 
SQL> desc OGG_1to1map;
ERROR:
ORA-04043: object OGG_1to1map does not exist 


SQL> create table ogg_1to1map (id number primary key,id_val varchar2(10));

Table created.

SQL> 
SQL> alter system switch logfile;

System altered.

SQL>

OGG - Source - Setting up the Env and process

Oracle GoldenGate Command Interpreter for Oracle
Version 11.1.1.1.2 OGGCORE_11.1.1.1.2_PLATFORMS_111004.2100
Windows (optimized), Oracle 11g on Oct  5 2011 00:50:57

Copyright (C) 1995, 2011, Oracle and/or its affiliates. All rights reserved.



GGSCI (HARI-PC) 1> info all

Program     Status      Group       Lag           Time Since Chkpt

MANAGER     STOPPED


GGSCI (HARI-PC) 2> add extract sr1_ext,tranlog,begin now
EXTRACT added.


GGSCI (HARI-PC) 3> add exttrail H:\OGG\SOURCE\dirdat\ex,extract sr1_ext
EXTTRAIL added.


GGSCI (HARI-PC) 4> dblogin userid hari,password ******
Successfully logged into database.

GGSCI (HARI-PC) 5> add trandata ogg_1to1map

Logging of supplemental redo data enabled for table HARI.OGG_1TO1MAP.

GGSCI (HARI-PC) 6> add extract sr1_pump,exttrailsource H:\OGG\SOURCE\dirdat\ex
EXTRACT added.


GGSCI (HARI-PC) 7> add rmttrail H:\OGG\TARGET\dirdat\rt,extract sr1_pump
RMTTRAIL added.


GGSCI (HARI-PC) 8> info all

Program     Status      Group       Lag           Time Since Chkpt

MANAGER     STOPPED
EXTRACT     STOPPED     SR1_EXT     00:00:00      00:07:36
EXTRACT     STOPPED     SR1_PUMP    00:00:00      00:06:41

AT Target - Setting up the process


Oracle GoldenGate Command Interpreter for Oracle
Version 11.1.1.1.2 OGGCORE_11.1.1.1.2_PLATFORMS_111004.2100
Windows (optimized), Oracle 11g on Oct  5 2011 00:50:57

Copyright (C) 1995, 2011, Oracle and/or its affiliates. All rights reserved.



GGSCI (HARI-PC) 1> info all

Program     Status      Group       Lag           Time Since Chkpt

MANAGER     STOPPED


GGSCI (HARI-PC) 2> dblogin userid puthranv@ogg,password *******
Successfully logged into database.

GGSCI (HARI-PC) 3>

GGSCI (HARI-PC) 3> add checkpointtable puthranv.chkp_ogg

Successfully created checkpoint table PUTHRANV.CHKP_OGG.

GGSCI (HARI-PC) 4> add replicat sr1_rep,exttrail H:\OGG\TARGET\dirdat\rt,checkpointtable puthranv.chkp_ogg
REPLICAT added.


GGSCI (HARI-PC) 5> info all

Program     Status      Group       Lag           Time Since Chkpt

MANAGER     STOPPED
REPLICAT    STOPPED     SR1_REP     00:00:00      00:04:53

Lets start the Oracle Goldengate Process and check run time messages 

Manager :-
GGSCI (HARI-PC) 9> start mgr

Manager started.

"========================================================================"
***********************************************************************
                 Oracle GoldenGate Manager for Oracle
     Version 11.1.1.1.2 OGGCORE_11.1.1.1.2_PLATFORMS_111004.2100 
        Windows (optimized), Oracle 11g on Oct  5 2011 00:28:27
 
Copyright (C) 1995, 2011, Oracle and/or its affiliates. All rights reserved.


                    Starting at 2013-06-09 13:08:37
***********************************************************************

Operating System Version:
Microsoft Windows 7 , on x86
Version 6.1 (Build 7600: )

Process id: 4136

Parameters...

PORT 1350
DYNAMICPORTLIST 12010-12030,1350,1230


***********************************************************************
**                     Run Time Messages                             **
***********************************************************************


2013-06-09 13:08:37  INFO    OGG-00983  Manager started (port 1350).
"========================================================================"

Starting Data Pump :-

GGSCI (HARI-PC) 10> start extract sr1_pump

Sending START request to MANAGER ...
EXTRACT SR1_PUMP starting
"========================================================================"
CACHEMGR virtual memory values (may have been adjusted)
CACHEBUFFERSIZE:                         64K
CACHESIZE:                                1G
CACHEBUFFERSIZE (soft max):               4M
CACHEPAGEOUTSIZE (normal):                4M
PROCESS VM AVAIL FROM OS (min):        1.75G
CACHESIZEMAX (strict force to disk):   1.55G

Database Version:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

Database Language and Character Set:
NLS_LANG = "AMERICAN_AMERICA.WE8MSWIN1252" 
NLS_LANGUAGE     = "AMERICAN" 
NLS_TERRITORY    = "AMERICA" 
NLS_CHARACTERSET = "WE8MSWIN1252" 

2013-06-09 13:09:14  INFO    OGG-01226  Socket buffer size set to 27985 (flush size 27985).

2013-06-09 13:09:14  INFO    OGG-01052  No recovery is required for target file H:\OGG\TARGET\dirdat\rt000000, at RBA 0 (file not opened).

2013-06-09 13:09:14  INFO    OGG-01478  Output file H:\OGG\TARGET\dirdat\rt is using format RELEASE 10.4/11.1.

***********************************************************************
**                     Run Time Messages                             **
***********************************************************************

Opened trail file H:\OGG\SOURCE\dirdat\ex000000 at 2013-06-09 13:09:18
TABLE resolved (entry HARI.OGG_1TO1MAP):
  TABLE HARI.OGG_1TO1MAP;
PASSTHRU mapping resolved for source table HARI.OGG_1TO1MAP
                  10 records processed as of 2013-06-09 13:45:58 (rate 0,delta 0)

2013-06-09 13:46:29  INFO    OGG-01021  Command received from GGSCI: STATS.

2013-06-09 14:00:41  INFO    OGG-01021  Command received from GGSCI: STOP.

***********************************************************************
*                   ** Run Time Statistics **                         *
***********************************************************************


Report at 2013-06-09 14:00:41 (activity since 2013-06-09 13:13:41)

Output to H:\OGG\TARGET\dirdat\rt:
"========================================================================"

Starting Extract :-


GGSCI (HARI-PC) 11> start extract sr1_ext

Sending START request to MANAGER ...
EXTRACT SR1_EXT starting
"========================================================================"
CACHEMGR virtual memory values (may have been adjusted)
CACHEBUFFERSIZE:                         64K
CACHESIZE:                                1G
CACHEBUFFERSIZE (soft max):               4M
CACHEPAGEOUTSIZE (normal):                4M
PROCESS VM AVAIL FROM OS (min):        1.75G
CACHESIZEMAX (strict force to disk):   1.55G

Database Version:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

Database Language and Character Set:
NLS_LANG = "AMERICAN_AMERICA.WE8MSWIN1252" 
NLS_LANGUAGE     = "AMERICAN" 
NLS_TERRITORY    = "AMERICA" 
NLS_CHARACTERSET = "WE8MSWIN1252" 

2013-06-09 13:09:18  WARNING OGG-01423  No valid default archive log destination directory found for thread 1.

2013-06-09 13:09:18  INFO    OGG-01515  Positioning to begin time Jun 9, 2013 1:00:43 PM.

2013-06-09 13:09:18  INFO    OGG-01052  No recovery is required for target file H:\OGG\SOURCE\dirdat\ex000000, at RBA 0 (file not opened).

2013-06-09 13:09:18  INFO    OGG-01478  Output file H:\OGG\SOURCE\dirdat\ex is using format RELEASE 10.4/11.1.

***********************************************************************
**                     Run Time Messages                             **
***********************************************************************


2013-06-09 13:09:18  INFO    OGG-01515  Positioning to begin time Jun 9, 2013 1:00:43 PM.

2013-06-09 13:09:18  INFO    OGG-01516  Positioned to Sequence 37, RBA 153104, Jun 9, 2013 1:00:43 PM.

2013-06-09 13:09:18  INFO    OGG-01517  Position of first record processed Sequence 37, RBA 153104, SCN 0.1773802, Jun 9, 2013 1:00:53 PM.
TABLE resolved (entry HARI.GGS_MARKER):
  TABLE HARI.GGS_MARKER;

Using the following key columns for source table HARI.GGS_MARKER: SEQNO, FRAGMENTNO, OPTIME.
TABLE resolved (entry HARI.OGG_1TO1MAP):
  TABLE HARI.OGG_1TO1MAP;

Using the following key columns for source table HARI.OGG_1TO1MAP: ID.
"========================================================================"

At the Target side

Starting Replicat:-
GGSCI (HARI-PC) 7> start replicat sr1_rep

Sending START request to MANAGER ...
REPLICAT SR1_REP starting
"========================================================================"
CACHEMGR virtual memory values (may have been adjusted)
CACHEBUFFERSIZE:                         64K
CACHESIZE:                              512M
CACHEBUFFERSIZE (soft max):               4M
CACHEPAGEOUTSIZE (normal):                4M
PROCESS VM AVAIL FROM OS (min):           1G
CACHESIZEMAX (strict force to disk):    881M

Database Version:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

Database Language and Character Set:
NLS_LANG = "AMERICAN_AMERICA.WE8MSWIN1252" 
NLS_LANGUAGE     = "AMERICAN" 
NLS_TERRITORY    = "AMERICA" 
NLS_CHARACTERSET = "WE8MSWIN1252" 

For further information on character set settings, please refer to user manual.

***********************************************************************
**                     Run Time Messages                             **
***********************************************************************

Opened trail file H:\OGG\TARGET\dirdat\rt000000 at 2013-06-09 13:09:37

MAP resolved (entry HARI.OGG_1TO1MAP):
  MAP HARI.OGG_1TO1MAP, TARGET puthranv.OGG_1to1map;
Using following columns in default map by name:
  ID, ID_VAL

Using the following key columns for target table PUTHRANV.OGG_1TO1MAP: ID.
"========================================================================"

Lets do some DML to check OGG replication

DML at Source
SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.07.56.034000 PM +05:30                                             

SQL> 
SQL> insert into ogg_1to1map select level,'ORACLE'||level from dual connect by level < 10;

9 rows created.

SQL> commit;

Commit complete.

SQL> select count(*) from ogg_1to1map;

  COUNT(*)                                                                      
----------                                                                      
         9                                                                      

SQL> 


Validating the DML at Target 

DML - Replicated to Target
SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.08.03.101000 PM +05:30                                             

SQL> 
SQL> 
SQL> select count(*) from ogg_1to1map;

  COUNT(*)                                                                      
----------                                                                      
         9                                                                      

lets see check the DDL replication too

DDL - At Source
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.16.35.561000 PM +05:30                                             

SQL> 
SQL> 
SQL> alter table ogg_1to1map add id_comp varchar2(10);

Table altered.

SQL> desc ogg_1to1map;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 ID_VAL                                             VARCHAR2(10)
 ID_COMP                                            VARCHAR2(10)

DDL - Validation at Target

At Target
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.16.40.738000 PM +05:30                                             

SQL> 
SQL> desc ogg_1to1map
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 ID_VAL                                             VARCHAR2(10)
 ID_COMP                                            VARCHAR2(10)

So far so good, lets see how Oracle treats Derived Objects, 

Derived Objects Replication At Source
SQL> 
SQL> create unique index hari.index_comp on hari.ogg_1to1map(id_comp);

Index created.

SQL> 
SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP';

INDEX_NAME                     TABLE_NAME                                       
------------------------------ ------------------------------                   
INDEX_COMP                     OGG_1TO1MAP                                      

SQL> 

Lets validate the replication of the Derived Object at Target

Derived Objects Replication At Target

SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.41.29.483000 PM +05:30                                             

SQL> 
SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP';

no rows selected

SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP';

no rows selected

SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP';

no rows selected

SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 01.45.59.396000 PM +05:30                                             

SQL>

Oh, what went wrong, my error log also doesn't say any thing too,

 2013-06-09 13:40:42  INFO    OGG-00482  Oracle GoldenGate Delivery for Oracle, 
SR1_REP.prm:  DDL found, operation [create unique index hari.index_comp on hari.ogg_1to1map(id_comp)  (size 65)].

2013-06-09 13:40:42  INFO    OGG-00489  Oracle GoldenGate Delivery for Oracle, 

SR1_REP.prm:  DDL is of mapped scope, after mapping new operation [create unique index hari.index_comp on "PUTHRANV"."OGG_1TO1MAP"(id_comp)  (size 73)].

2013-06-09 13:40:42  INFO    OGG-00487  Oracle GoldenGate Delivery for Oracle, 
SR1_REP.prm:  DDL operation included [INCLUDE MAPPED], optype [CREATE], objtype [INDEX], objowner [PUTHRANV], objname [OGG_1TO1MAP].

2013-06-09 13:40:42  INFO    OGG-00484  Oracle GoldenGate Delivery for Oracle, 
SR1_REP.prm:  Executing DDL operation.

2013-06-09 13:40:42  INFO    OGG-00483  Oracle GoldenGate Delivery for Oracle, 
SR1_REP.prm:  DDL operation successful.


Take a look at the transformation OGG is doing in processing the derived objects, object owner is modified as per the target environment. Ok all these looks nice, what is the issue, The ggserr shows DDL operation as success, but it is not replicated in the target DB. Isn't this a bug, have raised the same to Oracle Support. Lets see what happens to this.

             As an another option, Along with the one to one map i.,e MAP hari.OGG_1to1map, TARGET puthranv.OGG_1to1map in the Replicat parameter file, Include the wildcard search like - MAP hari.*, TARGET puthranv.*; Now let me re-test the derived objects replication on a new table.

Derived Objects - With Wildcard Search@Replicat Param. 
At Source

SQL> show user
USER is "HARI"
SQL> 
SQL> create table ogg_wildcard(id number primary key,id_val varchar2(10));

Table created.

SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 03.23.30.103000 PM +05:30                                             

SQL>

At Target
SQL> show user
USER is "PUTHRANV"
SQL> 
SQL> create table ogg_wildcard(id number primary key,id_val varchar2(10));

Table created.

SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 03.23.34.525000 PM +05:30                                             

SQL>


Lets create the Derived and Non-Derived Object 

At Source
SQL> create unique index hari.index_comp1 on hari.ogg_wildcard(id_comp);

Index created.

SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP1';

INDEX_NAME                     TABLE_NAME                                       
------------------------------ ------------------------------                   
INDEX_COMP1                    OGG_WILDCARD                                     

SQL> 
SQL> 
SQL> REM - Check non-derived objects creation
SQL> 
SQL> show user
USER is "HARI"
SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 03.33.17.254000 PM +05:30                                             

SQL> 
SQL> create index index_val1 on ogg_wildcard(id_val);

Index created.

SQL> select index_name,table_name from user_indexes where index_name='INDEX_VAL1';

INDEX_NAME                     TABLE_NAME                                       
------------------------------ ------------------------------                   
INDEX_VAL1                     OGG_WILDCARD                                     

SQL>

At Target - Validating the Derived and Non-Derived Object replication

SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 03.31.10.720000 PM +05:30                                             

SQL> 
SQL> select index_name,table_name from user_indexes where index_name='INDEX_COMP1';

INDEX_NAME                     TABLE_NAME                                       
------------------------------ ------------------------------                   
INDEX_COMP1                    OGG_WILDCARD                                     

SQL> REM - The Derived Index is created above which is not happening in 1to1map
SQL> 
SQL> select systimestamp from dual;

SYSTIMESTAMP                                                                    
---------------------------------------------------------------------------     
09-JUN-13 03.34.36.039000 PM +05:30                                             

SQL> 
SQL> select index_name,table_name from user_indexes where index_name='INDEX_VAL1';

INDEX_NAME                     TABLE_NAME                                       
------------------------------ ------------------------------                   
INDEX_VAL1                     OGG_WILDCARD                                     

SQL> 
SQL> REM - Non-derived index is created above
SQL> 

    Yes the derived objects are replicated when wildcard search ( MAP hari.*, TARGET puthranv.*;)are included in replicat parameter.

                   Why derived objects are replicated only with wildcard search and not with one to one mapping, OGG doc's has given examples using wildcard search but has never pointed that  derived objects wok only with wildcard search. Have raised the same to Oracle Support. Lets wait :)

Friday, May 31, 2013

Compare Oracle Collections

In programming we don't just compare variables/integers with each other, we tend to compare arrays too. Collections aka arrays can be compared in different ways, lets see them in detail.

Traditional Method

Option 1
               The traditional method to compare collection would be just to loop through them and compare one with another, like below         
SQL> set timing on
SQL> 
SQL> set serveroutput on
SQL> declare
  2  type basket is table of number;
  3  num_balls basket := basket(1,2,3);
  4  num_color_balls basket := basket(3,2,1);
  5  inter_match number:=0;
  6  begin
  7  if num_balls.count = num_color_balls.count then
  8    for i in num_balls.first .. num_balls.last loop
  9      for j in num_color_balls.first .. num_color_balls.last loop
 10        if num_balls(i) = num_color_balls(j) then
 11            inter_match := inter_match+1;
 12        end if;
 13      end loop;
 14    end loop;
 15    if inter_match = num_balls.count then
 16        dbms_output.put_line('Arrays are equal');
 17    end if;
 18  else
 19  dbms_output.put_line('Arrays are not equal');
 20  end if;
 21  end;
 22  /
Arrays are equal                                                                

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.04
SQL> 

Option 2 
              Using Table Cast with MINUS operator thus avoiding loops

SQL> 
SQL> create type basket is table of number;
  2  /

Type created.

Elapsed: 00:00:00.72
SQL> 
SQL> declare
  2  num_balls basket := basket(1,2,3);
  3  num_color_balls basket := basket(3,2,1);
  4  v_count number;
  5  
  6  begin
  7  
  8  select column_value into v_count from
  9  (
 10  (select column_value from table(cast(num_balls as basket)))
 11  minus
 12  (select column_value from table(cast(num_color_balls as basket)))
 13  );
 14  
 15  if v_count>0 then
 16  dbms_output.put_line('Arrays are not equal');
 17  end if;
 18  
 19  exception
 20  when no_data_found then
 21  dbms_output.put_line('Arrays are equal');
 22  
 23  end;
 24  /
Arrays are equal                                                                

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
SQL> 

You will have to go only with the above two options until Oracle 10g, From 10g we have got many options to compare collections, lets see them in detail. 

 Comparing collection is now as same as comparing variables/integers, example given below
SQL> 
SQL> declare
  2  num_balls basket := basket(1,2,3);
  3  num_color_balls basket := basket(1,2,3);
  4  begin
  5    if num_balls = num_color_balls then
  6      dbms_output.put_line('Arrays are equal');
  7    else
  8      dbms_output.put_line('Arrays are not equal');
  9    end if;
 10  end;
 11  /
Arrays are equal                                                                

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
SQL> 

Note : The order of elements in an array is irrelevant while comparing collections. It means that an array with data 1,2,3 is equal to 3,2,1 and that's what we have seen above. Ok this is fine, can we do the same with Associative and Varrays 

Varrays

SQL> 
SQL> declare
  2  --type basket is table of number;
  3  type basket is varray(10) of number;
  4      num_balls basket := basket(1,2,3);
  5      num_color_balls basket := basket(1,2,3);
  6      begin
  7        if num_balls = num_color_balls then
  8          dbms_output.put_line('Arrays are equal');
  9        else
 10          dbms_output.put_line('Arrays are not equal');
 11        end if;
 12     end;
 13     /
      if num_balls = num_color_balls then
                   *
ERROR at line 7:
ORA-06550: line 7, column 20: 
PLS-00306: wrong number or types of arguments in call to '=' 
ORA-06550: line 7, column 7: 
PL/SQL: Statement ignored 

Elapsed: 00:00:00.01
SQL> 

Means you cannot compare all elements at one shot, have to do it one by one

SQL> 
SQL> declare
  2  --type basket is table of number;
  3  type basket is varray(10) of number;
  4      num_balls basket := basket(1,2,3);
  5      num_color_balls basket := basket(1,2,3);
  6      begin
  7        if num_balls(1) = num_color_balls(1) then
  8          dbms_output.put_line('Arrays are equal');
  9        else
 10          dbms_output.put_line('Arrays are not equal');
 11        end if;
 12     end;
 13     /
Arrays are equal                                                                

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SQL> 

Associative Array - Cannot be compared at one shot, should be looped,

SQL> REM ASSOCIATIVE ARRAYS
SQL> 
SQL> declare
  2  type basket is table of number index by pls_integer;
  3      num_balls basket;
  4      num_color_balls basket;
  5      begin
  6      select level bulk collect into num_balls from dual connect by level < 10;
  7      select level bulk collect into num_color_balls from dual connect by level < 10;
  8        if num_balls = num_color_balls then
  9          dbms_output.put_line('Arrays are equal');
 10        else
 11          dbms_output.put_line('Arrays are not equal');
 12        end if;
 13     end;
 14     /
      if num_balls = num_color_balls then
                   *
ERROR at line 8:
ORA-06550: line 8, column 20: 
PLS-00306: wrong number or types of arguments in call to '=' 
ORA-06550: line 8, column 7: 
PL/SQL: Statement ignored 


Elapsed: 00:00:00.01
SQL> 
SQL> 
SQL> declare
  2  type basket is table of number index by pls_integer;
  3      num_balls basket;
  4      num_color_balls basket;
  5      begin
  6      select level bulk collect into num_balls from dual connect by level < 10;
  7      select level bulk collect into num_color_balls from dual connect by level < 10;
  8        if num_balls(1) = num_color_balls(1) then
  9          dbms_output.put_line('Arrays are equal');
 10        else
 11          dbms_output.put_line('Arrays are not equal');
 12        end if;
 13     end;
 14     /
Arrays are equal                                                                

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
SQL>  
Will see about Multiset operators in the next post.

Thursday, May 16, 2013

Partitions- Kind of Global Vs Local Partitioned Indexes

Had a great discussion with few techi folks today. It started with SQL tuning (my area of interest ) and eventually partitioning. I was sticking towards SQL Tuning + Partition Elimination + Global Indexes.  And they were sticking towards Full table Scan + Maintenance Activities + Local Indexes. The discussion was heating up and i made up my mind to switch lane :) when two more AK47 was kept before, yes Partitioned table with Tera Bytes of data + Archiving Strategy. 

             Does this look like OLTP vs OLAP. Big Table Maintenance + Archiving Strategy would shatter the usage of global indexes, but lets see what happens when global indexes are not present. Let's see them in detail. 

SQL> set timing on
SQL> 
SQL> drop table t2;

Table dropped.

Elapsed: 00:00:00.40
SQL> 
SQL> CREATE TABLE t2
  2      (
  3        x   int not null primary key,
  4        dt  date,
  5        y   varchar2(30)
  6      )
  7      PARTITION BY RANGE(dt)
  8      (
  9      PARTITION part1_FEB2013 VALUES LESS THAN (to_date('01-Feb-2013','dd-mon-yyyy')) ,
 10      PARTITION part1_MAR2013 VALUES LESS THAN (to_date('01-Mar-2013','dd-mon-yyyy')) ,
 11      PARTITION part1_APR2013 VALUES LESS THAN (to_date('01-Apr-2013','dd-mon-yyyy')) ,
 12      PARTITION part2_MAY2013 VALUES LESS THAN (to_date('01-May-2013','dd-mon-yyyy')),
 13      PARTITION junk VALUES LESS THAN (MAXVALUE)
 14     );

Table created.

Elapsed: 00:00:00.10
SQL> 
SQL> create index idx_y on t2(y);

Index created.

Elapsed: 00:00:00.03
SQL>
Loading data
SQL> insert into t2 values (1,sysdate-120,'ORACLE');

1 row created.

Elapsed: 00:00:00.02
SQL> insert into t2 values (2,sysdate-90,'ORACLE');

1 row created.

Elapsed: 00:00:00.02
SQL> insert into t2 values (3,sysdate-60,'ORACLE');

1 row created.

Elapsed: 00:00:00.03
SQL> insert into t2 values (4,sysdate-30,'ORACLE');

1 row created.

Elapsed: 00:00:00.01
SQL> insert into t2 values (5,sysdate,'ORACLE');

1 row created.

Elapsed: 00:00:00.02
SQL> commit;

Commit complete.

Elapsed: 00:00:00.00
SQL>
Lets check the status of my indexes
SQL> select index_name,status from user_indexes where table_name ='T2';

INDEX_NAME                     STATUS                                           
------------------------------ --------                                         
IDX_Y                          VALID                                            
SYS_C0012417                   VALID                                            

Elapsed: 00:00:00.08

As part of archiving strategy lets drop a Partition
SQL> alter table t2 drop partition part2_MAY2013;

Table altered.

Elapsed: 00:00:00.07
SQL> 
SQL> select index_name,status from user_indexes where table_name='T2'
  2  ;

INDEX_NAME                     STATUS                                           
------------------------------ --------                                         
IDX_Y                          UNUSABLE                                         
SYS_C0012417                   UNUSABLE                                         

Elapsed: 00:00:00.04
SQL>


Dropping partition leading to un-usability of indexes, If i create a Global Index, then would be looking forward to use my Global Index though skip_unusable_indexes defaults to true in Oracle 11g. In general archiving strategy can include the below options 

1. Drop Partition with Update Indexes Clause.Update Global Index makes you wait 
2. Truncate partition(Partition wise) with Update Indexes option + Drop Partition
3. Drop Partition + Rebuild the Index 
4. Delete data partition wise + Drop partition - Delete would update the Global Index And the easiest way would be
5. Drop partitions - Table without Global Indexes. 

 Now the question here is if we have to create a table without global index, how would the primary key look like,

SQL> CREATE TABLE t2
  2      (
  3        x   int not null,
  4        dt  date not null,
  5        y   varchar2(30)
  6      )
  7      PARTITION BY RANGE(dt)
  8      (
  9      PARTITION part1_FEB2013 VALUES LESS THAN (to_date('01-Feb-2013','dd-mon-yyyy')) ,
 10      PARTITION part1_MAR2013 VALUES LESS THAN (to_date('01-Mar-2013','dd-mon-yyyy')) ,
 11       PARTITION part1_APR2013 VALUES LESS THAN (to_date('01-Apr-2013','dd-mon-yyyy')) ,
 12       PARTITION part2_MAY2013 VALUES LESS THAN (to_date('01-May-2013','dd-mon-yyyy')),
 13       PARTITION junk VALUES LESS THAN (MAXVALUE)
 14     );

Table created.       
Lets create the unique index on column x
SQL> 
SQL> create unique index idx_xdt on t2(x) local;
create unique index idx_xdt on t2(x) local
                               *
ERROR at line 1:
ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index 
In just simple words, it means that the partition key and key columns should have a link

SQL> REM - Lets create it in the form of a subset of key columns
SQL> 
SQL> create unique index idx_xdt on t2(x,dt) local;

Index created.
SQL> 
SQL> 
SQL> create index idx_y on t2(y);

Index created.
SQL> 
SQL> 
SQL> insert into t2 values (1,sysdate-120,'ORACLE');

1 row created.

SQL> insert into t2 values (2,sysdate-90,'ORACLE');

1 row created.

SQL> insert into t2 values (3,sysdate-60,'ORACLE');

1 row created.

SQL> insert into t2 values (4,sysdate-30,'ORACLE');

1 row created.

SQL> insert into t2 values (5,sysdate,'ORACLE');

1 row created.

SQL> commit;

Commit complete.
And now their impact over dropping partitions

SQL> 
SQL> select index_name,status from user_indexes where table_name in('T2');

INDEX_NAME                     STATUS                                           
------------------------------ --------                                         
IDX_Y                          VALID                                            
IDX_XDT                        N/A                                              

SQL> 
SQL> select index_name,locality from user_part_indexes where table_name in('T2');

INDEX_NAME                     LOCALI                                           
------------------------------ ------                                           
IDX_XDT                        LOCAL                                            

SQL> 
SQL> 
SQL> alter table t2 drop partition part2_MAY2013;

Table altered.

SQL> 
SQL> select index_name,status from user_indexes where table_name='T2';

INDEX_NAME                     STATUS                                           
------------------------------ --------                                         
IDX_Y                          UNUSABLE                                         
IDX_XDT                        N/A                                              

SQL> 

The actual core issue is GLOBAL INDEX becoming unusable and then they have to be rebuild. It really becomes too time consuming when the table is huge and DBA's would often start praying when they rebuild index

SQL> 
SQL> alter index idx_y rebuild;

Index altered.

SQL> select index_name,status from user_indexes where table_name='T2';

INDEX_NAME                     STATUS                                           
------------------------------ --------                                         
IDX_Y                          VALID                                            
IDX_XDT                        N/A                                              

SQL>

So worried about rebuilding global index post dropping a partition as part of archival strategy, Now lets see what happens when we don't have global index. To demonstrate the same, let me create a table with 133 partitions,

drop table t2;
CREATE TABLE t2
        (
          x   int not null,
          dt  date not null,
          y   varchar2(30)
        )
        PARTITION BY RANGE(dt)
        (
PARTITION part1_JAN2003 VALUES LESS THAN (to_date('01-JAN-2003','dd-mon-yyyy')) ,
PARTITION part1_FEB2003 VALUES LESS THAN (to_date('01-FEB-2003','dd-mon-yyyy')) ,
PARTITION part1_MAR2003 VALUES LESS THAN (to_date('01-MAR-2003','dd-mon-yyyy')) ,
PARTITION part1_APR2003 VALUES LESS THAN (to_date('01-APR-2003','dd-mon-yyyy')) ,
PARTITION part1_MAY2003 VALUES LESS THAN (to_date('01-MAY-2003','dd-mon-yyyy')) ,
PARTITION part1_JUN2003 VALUES LESS THAN (to_date('01-JUN-2003','dd-mon-yyyy')) ,
PARTITION part1_JUL2003 VALUES LESS THAN (to_date('01-JUL-2003','dd-mon-yyyy')) ,
PARTITION part1_AUG2003 VALUES LESS THAN (to_date('01-AUG-2003','dd-mon-yyyy')) ,
PARTITION part1_SEP2003 VALUES LESS THAN (to_date('01-SEP-2003','dd-mon-yyyy')) ,
PARTITION part1_OCT2003 VALUES LESS THAN (to_date('01-OCT-2003','dd-mon-yyyy')) ,
PARTITION part1_NOV2003 VALUES LESS THAN (to_date('01-NOV-2003','dd-mon-yyyy')) ,
PARTITION part1_DEC2003 VALUES LESS THAN (to_date('01-DEC-2003','dd-mon-yyyy')) ,
PARTITION part1_JAN2004 VALUES LESS THAN (to_date('01-JAN-2004','dd-mon-yyyy')) ,
PARTITION part1_FEB2004 VALUES LESS THAN (to_date('01-FEB-2004','dd-mon-yyyy')) ,
PARTITION part1_MAR2004 VALUES LESS THAN (to_date('01-MAR-2004','dd-mon-yyyy')) ,
PARTITION part1_APR2004 VALUES LESS THAN (to_date('01-APR-2004','dd-mon-yyyy')) ,
PARTITION part1_MAY2004 VALUES LESS THAN (to_date('01-MAY-2004','dd-mon-yyyy')) ,
PARTITION part1_JUN2004 VALUES LESS THAN (to_date('01-JUN-2004','dd-mon-yyyy')) ,
PARTITION part1_JUL2004 VALUES LESS THAN (to_date('01-JUL-2004','dd-mon-yyyy')) ,
PARTITION part1_AUG2004 VALUES LESS THAN (to_date('01-AUG-2004','dd-mon-yyyy')) ,
PARTITION part1_SEP2004 VALUES LESS THAN (to_date('01-SEP-2004','dd-mon-yyyy')) ,
PARTITION part1_OCT2004 VALUES LESS THAN (to_date('01-OCT-2004','dd-mon-yyyy')) ,
PARTITION part1_NOV2004 VALUES LESS THAN (to_date('01-NOV-2004','dd-mon-yyyy')) ,
PARTITION part1_DEC2004 VALUES LESS THAN (to_date('01-DEC-2004','dd-mon-yyyy')) ,
PARTITION part1_JAN2005 VALUES LESS THAN (to_date('01-JAN-2005','dd-mon-yyyy')) ,
......
PARTITION part1_DEC2013 VALUES LESS THAN (to_date('01-DEC-2013','dd-mon-yyyy')) ,
PARTITION junk VALUES LESS THAN (MAXVALUE)
);
Table created.

SQL>
SQL> create unique index idx_xdt on t2(x,dt) local;

Index created.
SQL> select partition_count from user_part_tables where table_name = 'T2';

PARTITION_COUNT                                                                 
---------------                                                                 
            133 

Have loaded 12,60,000 records, which is off-course very tiny. Loaded using similar statements like below,

insert into t2 
select level, 
       to_date('01-JUL-2003','dd-mon-yyyy')+ mod(level,30),
       'ORACLE'||mod(level,1000) 
from dual 
connect by level < 10001; 
The records are spread across evenly, like below
SQL> select count(*),y from t2 group by y;

  COUNT(*) Y                                                                    
---------- ------------------------------                                       
      1260 ORACLE90                                                             
      1260 ORACLE101                                                            
      1260 ORACLE102                                                            
      1260 ORACLE107                                                            
      1260 ORACLE110                                                            
      1260 ORACLE118                                                            
      1260 ORACLE124                                                            
      1260 ORACLE132                                                            
      1260 ORACLE141                                                            
      1260 ORACLE157                                                            
      1260 ORACLE163                                                            
      1260 ORACLE171                                                            
      1260 ORACLE172                                                            
      1260 ORACLE177                                                            
      1260 ORACLE181                                                            
      1260 ORACLE185                      

....

Lets create a global index on column- Y
SQL> create index idx_y on t2(y) global;

Index created.
Elapsed: 00:00:31.30
SQL> exec dbms_stats.gather_table_stats('HARI','T2');

PL/SQL procedure successfully completed.

Elapsed: 00:00:44.39
SQL> 

Issue the culprit :)
SQL> update t2 set y='ORACLE_ORACLE' where x = 124587;

1 row updated.

Elapsed: 00:00:00.00
SQL> commit;

Commit complete.

Elapsed: 00:00:00.00
SQL> 
Lets check the selection part,
SQL> alter system flush shared_pool;

System altered.

Elapsed: 00:00:12.13
SQL> 
SQL> alter system flush buffer_cache;

System altered.

Elapsed: 00:00:00.11

SQL> select * from t2 where y='ORACLE_ORACLE';

         X DT        Y                                                          
---------- --------- ------------------------------                             
    124587 28-JUL-04 ORACLE_ORACLE                                              

Elapsed: 00:00:01.37
SQL> 
SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT                                                               
--------------------------------------------------------------------------------
SQL_ID  c6tupfvyvdyaq, child number 0                                           
-------------------------------------                                           
select * from t2 where y='ORACLE_ORACLE'                                        
                                                                                
Plan hash value: 2614863613                                                     
                                                                                
------------------------------------------------------------------------------------------------------------                                                    
| Id  | Operation                          | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |                                                    
------------------------------------------------------------------------------------------------------------                                                    
|   0 | SELECT STATEMENT                   |       |       |       |  1265 (100)|          |       |       |                                                    
|   1 |  TABLE ACCESS BY GLOBAL INDEX ROWID| T2    |  1259 | 28957 |  1265   (0)| 00:00:16 | ROWID | ROWID |                                                    
|*  2 |   INDEX RANGE SCAN                 | IDX_Y |  1259 |       |     7   (0)| 00:00:01 |       |       |                                                    
------------------------------------------------------------------------------------------------------------                                                    
                                                                               
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
   2 - access("Y"='ORACLE_ORACLE')                                              

19 rows selected.

Elapsed: 00:00:02.68
SQL> 

Let me drop the Global Index and check the same
SQL> drop index idx_y;

Index dropped.
Elapsed: 00:00:01.68
SQL> 
SQL> select * from t2 where y='ORACLE_ORACLE';

         X DT        Y                                                          
---------- --------- ------------------------------                             
    124587 28-JUL-04 ORACLE_ORACLE                                              

Elapsed: 00:00:05.72
SQL> 
SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT                                                               
--------------------------------------------------------------------------------
SQL_ID  c6tupfvyvdyaq, child number 0                                           
-------------------------------------                                           
select * from t2 where y='ORACLE_ORACLE'                                        
                                                                                
Plan hash value: 2884929167                                                     
                                                                                
--------------------------------------------------------------------------------------------                                                                    
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |                                                                    
--------------------------------------------------------------------------------------------                                                                    
|   0 | SELECT STATEMENT    |      |       |       |  1486 (100)|          |       |       |                                                                    
|   1 |  PARTITION RANGE ALL|      |  1260 | 28980 |  1486   (2)| 00:00:18 |     1 |   133 |                                                                    
|*  2 |   TABLE ACCESS FULL | T2   |  1260 | 28980 |  1486   (2)| 00:00:18 |     1 |   133 |                                                                    
--------------------------------------------------------------------------------------------                                                                    
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
   2 - filter("Y"='ORACLE_ORACLE')                                              
19 rows selected.

Elapsed: 00:00:02.47
SQL> 

As expected Partition Elimination doesn't happen and the optimizer has to look into all the partition. Though the elapsed time for FTS + Partition ALL is slightly cheaper in this case, we will have to pay when the table grows and Partition Pruning doesn't happen. Global Indexes helps us in identifying the partition. But for a moment do you think you can go with Local Index, Ok lets check that too :)

SQL> create index idx_local_y on t2(y) local;

Index created.

Elapsed: 00:00:11.94
SQL> select index_name, locality from user_part_indexes where table_name='T2';

INDEX_NAME                     LOCALI                                           
------------------------------ ------                                           
IDX_XDT                        LOCAL                                            
IDX_LOCAL_Y                    LOCAL                                            

Elapsed: 00:00:00.23
SQL> 
SQL> select * from t2 where y='ORACLE_ORACLE';

         X DT        Y                                                          
---------- --------- ------------------------------                             
    124587 28-JUL-04 ORACLE_ORACLE                                              

Elapsed: 00:00:03.26
SQL> 
SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT                                                               
--------------------------------------------------------------------------------
SQL_ID  c6tupfvyvdyaq, child number 0                                           
-------------------------------------                                           
select * from t2 where y='ORACLE_ORACLE'                                        
                                                                                
Plan hash value: 2685712566                                                     
                                                                                
------------------------------------------------------------------------------------------------------------------                                              
| Id  | Operation                          | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |                                              
------------------------------------------------------------------------------------------------------------------                                              
|   0 | SELECT STATEMENT                   |             |       |       |  1396 (100)|          |       |       |                                              
|   1 |  PARTITION RANGE ALL               |             |  1259 | 28957 |  1396   (1)| 00:00:17 |     1 |   133 |                                              
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| T2          |  1259 | 28957 |  1396   (1)| 00:00:17 |     1 |   133 |                                              
|*  3 |    INDEX RANGE SCAN                | IDX_LOCAL_Y |  1259 |       |   137   (0)| 00:00:02 |     1 |   133 |                                              
------------------------------------------------------------------------------------------------------------------                                              
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
   3 - access("Y"='ORACLE_ORACLE')                                              
                                                                                

20 rows selected.

Elapsed: 00:00:05.22
 


The above is a clear example of reading multiple volumes of a book with each chapter being identified through Book Index :), Got it, i.e, the local index is being used to read all partitions of the table. 

Conclusion 
         Can partitioned table exists without a Single Global Index.Yes, Rebuilding Index is a nightmare in few circumstances, but at what cost, shouldn't i help the optimizer in performing Partition Pruning through Global Index. Dropping Partitions-Wise is definitely the efficient/effective and easiest way to perform data archival(Facilitated through Local Index). Its always Benefit Vs Cost, It is up to the application/architect team is decide to achieve maximum benefit.

Thursday, April 11, 2013

Locks in Oracle - Part 2

Transaction--> Locks
  1. How is my transaction tracked 
  2. How does oracle ensures or rather maintains data integrity and table definition integrity during the due course of my transaction
  3. How is lock escalation handled in Oracle
  4. Where is the Lock info stored in Oracle
Does these question are of your interest, then proceed reading below,  
A transaction begins with a DML/Select FOR UPDATE and ends with commit, rollback or  even with a DDL. Every transaction is identified with a unique transaction ID.  Let's try it out, 

SQL> 
SQL> update t1 set id_val='ORC' where id = 1;

1 row updated.

Elapsed: 00:00:00.16
SQL>
Lets check for the transaction ID
SQL> 
SQL> select xid from v$transaction;

XID                                                                             
----------------                                                                
01000C0083060000                                                                

Elapsed: 00:00:00.01
SQL>

If you would like to see the decimal notation of the transaction id, then try below
SQL> 
SQL> select dbms_transaction.local_transaction_id from dual;

LOCAL_TRANSACTION_ID                                                            
--------------------------------------------------------------------------------
1.12.1667                                                                       

Elapsed: 00:00:00.02
The transaction ID has three parts in it, Rollback Segment number, Slot Number and a Wrap Number. Lets check the v$transaction to validate the same,

SQL> select xid,ADDR,XIDUSN,XIDSLOT,XIDSQN from v$transaction;

XID              ADDR         XIDUSN    XIDSLOT     XIDSQN                      
---------------- -------- ---------- ---------- ----------                      
01000C0083060000 3B0F7554          1         12       1667                      

Elapsed: 00:00:00.01
SQL>
Well the column significance are 

XIDUSN   - Transaction ID's Undo Segment Number 
XIDSLOT - Transaction ID's Slot Number 
XIDSQN   - Transaction ID's Sequence Number
           Transaction ID is the single identifier which would help us to proceed further with the series of investigation,
SQL> 
SQL> select * from v$locked_object;

   XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID   ORACLE_USERNAME   OS_USER_NAME   PROCESS   LOCKED_MODE                                            
---------- ---------- ---------- ---------- ----------  ---------------- --------------- --------- -----------                                            
    1          12        1667      74916        203              HARI      HARI-PC\HARI  6076:5924  3                                            
                                                                                
Elapsed: 00:00:00.05
SQL>

LOCKED_MODE in v$locked_Object indicates in what mode the Object_ID is locked. In our case the Object_Id 74916 (Table Name - T2) is locked in SX(Row- Exclusive) mode i.,e "Rows are locked in the table in exclusive mode", Now lets see the types of locks the transaction is holding,

SQL> 
SQL> select * from v$lock where sid=203;

ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST       CTIME      BLOCK      
-------- -------- ---------- -- ---------- ---------- ---------- ----------     ---------- ----------   
3D378880 3D3788AC        203 AE        100          0          4          0         435          0      
0EEB6AA0 0EEB6AD0        203 TM      74916          0          3          0          13          0      
3B0F7554 3B0F7594        203 TX      65548       1667          6          0          13          0      
                                                                                

Elapsed: 00:00:00.05
SQL> 

v$Lock helps us to identify the types of locks associated with the transaction. The locks bundled with the transaction are AE,TM, TX. Keeping aside AE at the moment lets see what these TX and TM are,


TX Lock/Enqueue - This represents the transaction and are enforced to maintain data integrity.  Its the Row-Level locking, a modified row is always locked in exclusive manner so that other users cannot modify the row unless untill the parent transaction ends. And that's the reason it shows LMODE = 6 indicating exclusive lock on the row and REQUEST = 0 means am holding the lock and am the owner, therefore doesn't request any. The ID1(usn+slot) and ID2(seq) together represents the transaction ID. This exclusive lock doesn't mean DML are prohibited on the table, it's only on that particular row so that other session cannot modify it. So a lock is never escalated it can only be released when the transaction ends.

TM Lock/Enqueue - This represents the table and they lock the table from structural change, ensuring no change to data definition of the table during the due course of the transaction. And that's the reason it shows LMODE = 3 indicating rows are locked in exclusive mode in this table. ID1 shows the Object_ID being locked.

Oracle doesn't have the concept of Lock Manager which would normally act as the central locking system to handle locks in few database's, remember a central locking is prone to contention. In oracle the lock info is stored right at the block itself. The Data Block holds the lock bit information which in turn points to the ITL - Interested Transaction List and this in turn points to the undo segment header to validate the validity of the data.

Sunday, April 7, 2013

Locks in Oracle - Part 1

Apart from parsing
  1. What happens when i issue an update statement ?
  2. How does Oracle comply with the properties of a Database Transaction aka ACID properties
If interested read further :)

A transaction is nothing but SQL statements which is tracked with an unique transaction ID until commit / rollback / DDL are issued. ooh ooh hold on, before i get into the internals lets have a quick view on the basic's of Locks.

Is this true - "Picture Speaks Louder Than Words"

For the next series of diagrams concentrate on the below arrow in each diagram- 










Lets start with a basic query and check what happens
Step-1

















Step-2

























Step-3


























Step-4



























Step-5































Step-6































Step-7































does these diagrams helped you to understand something, will continue internals soon