Friday, May 8, 2009

Resumable space allocation

Long running operations or batch process would fail due to insufficient space. When job fails, DBA has to allocate the space and restart the job manually. When DBA restarts the job, oracle has to run the job from the scratch again. Oracle9i introduced Resumable space allocation to resolve this kind of issues.

With this resumable space allocation feature, whenever job fails, it will be suspended until DBA fix the issues and job will be resumed instead of restarting from scratch.

In oracle9i, resumable space allocation feature must be turned on in the session level using the ALTER SESSION ENABLE RESUMABLE statement. In oracle10g, a new parameter RESUMABLE_TIMEOUT was introduced, where the resumable space allocation feature can be turned on at the database level. The default for this parameter is 0, which means the resumable timeout is not enabled.

Steps to setup Resumable space allocation:

Let us assume, we are enabling resumable job allocation for scott user.

Step1.

We need to grant RESUMABLE system privileges to schema.

GRANT RESUMABLE TO SCOTT;

Step2.

We need to setup the resumable timeout in seconds. The operation will be suspended for specified number of seconds for DBA to fix the problem.

There are several ways we can set timeout parameter.

ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600;

EXECUTE Dbms_Resumable.Set_Timeout(3600);

ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600 NAME 'emp data loading';

We can set RESUMABLE_TIMEOUT parameter in init parameter file. This new parameter was introduced in oracle10g. Resumable space allocation feature will be disabled automatically when RESUMABLE_TIMEOUT parameter is zero. We can set this parameter in session level as well as database level.

alter session set resumable_timeout=3600;
alter system set resumable_timeout=3600;

What kind of issues can be suspended in resumable space allocation?

Out of space:

We have an out of space error when we can not get any more extents for various database objects in a tablespace.

Maximum extents reached:

Number of extents are exceeded the maximum extents which we specified for the object.

Space Quota Exceeded:

User exceeds the space quota for the tablespace. when we create the user, we set the space quota. Operation will be suspended when user exceeds the space quota on tablespace.

What kind of operations can fall into resumable space allocation?

1. Queries that run out of temporary space for sorting.
2. DML Insert, update statement
3. DDL Create table as select, alter table, create index, alter index,
create materialized view, create materialized view log etc
4. Import/export
5. SQL Loader

Let us test resumable space allocation on scott schema. The below PLSQL code runs without resumable space allocation. When we run this code, it is failed right away....

scott@orcl> alter session set resumable_timeout=0;

Session altered.

scott@orcl> begin
2 for i in 1 .. 5000
3 loop
4 insert into employee
5 select * from employee;
6 commit;
7 end loop;
8 end;
9 /
begin
*
ERROR at line 1:
ORA-01653: unable to extend table SCOTT.EMPLOYEE by 8 in tablespace USERSPACE
ORA-06512: at line 4

scott@orcl>

Let us test the same code with resumable space allocation. Now i set the timeout parmeter 60 seconds. The session suspends for 60 seconds and throw error. Since we did not fix the error during the 60 seconds.

scott@orcl> alter session set resumable_timeout=60;

Session altered.

scott@orcl> set time on
11:37:24 scott@orcl>
11:37:24 scott@orcl> begin
11:37:24 2 for i in 1 .. 5000
11:37:24 3 loop
11:37:24 4 insert into employee
11:37:24 5 select * from employee;
11:37:24 6 commit;
11:37:24 7 end loop;
11:37:24 8 end;
11:37:24 9 /
begin
*
ERROR at line 1:
ORA-30032: the suspended (resumable) statement has timed out
ORA-01653: unable to extend table SCOTT.EMPLOYEE by 8 in tablespace USERSPACE
ORA-06512: at line 4

11:38:26 scott@orcl>

Let us test the same PLSQL code with higher timeout seconds. Let me set 1000 seconds.

scott@orcl> ALTER SESSION ENABLE RESUMABLE TIMEOUT 1000 NAME 'emp data loading';

Session altered.

scott@orcl> begin
2 for i in 1 .. 10
3 loop
4 insert into employee
5 select * from employee;
6 commit;
7 end loop;
8 end;
9 /

The above PLSQL procedure is hanging... Let me connect another session and check the status.

scott@orcl> connect scott/tiger@orcl
Connected.
system@orcl> select name,sql_text,status,error_msg from dba_resumable;

NAME
--------------------------------------------------------------------------------
SQL_TEXT
--------------------------------------------------------------------------------
STATUS
---------
ERROR_MSG
--------------------------------------------------------------------------------
emp data loading
INSERT INTO EMPLOYEE SELECT * FROM EMPLOYEE
SUSPENDED
ORA-01653: unable to extend table SCOTT.EMPLOYEE by 8 in tablespace USERSPACE

scott@orcl>

It seems like, the session is suspended and waiting the space to load the data. Let me connect in another session and increase the space for the tablespace.

system@orcl> connect system/password@orcl
Connected.
system@orcl> alter database datafile
2 'C:\ORACLE\PRODUCT\10.1.0\ORADATA\ORCL\USERSPACE.DBF' resize 1000M;

Database altered.

system@orcl>

Again i will check the status of this job.

scott@orcl> connect scott/tiger@orcl
Connected.
scott@orcl> select name,sql_text,status,error_msg from dba_resumable;

NAME
--------------------------------------------------------------------------------
SQL_TEXT
--------------------------------------------------------------------------------
STATUS
---------
ERROR_MSG
--------------------------------------------------------------------------------
User SCOTT(57), Session 132, Instance 1
INSERT INTO EMPLOYEE SELECT * FROM EMPLOYEE
NORMAL

scott@orcl>

As per the above query, the status is back to normal. It means, the job is resumed. The error message is disappeared.

Again i went back and checked the job. The job is also successfully completed after increasing the space.

scott@orcl> begin
2 for i in 1 .. 10
3 loop
4 insert into employee
5 select * from employee;
6 commit;
7 end loop;
8 end;
9 /

PL/SQL procedure successfully completed.

scott@orcl>

Usage of AFTER SUSPEND TRIGGER:

It is impossible to check the suspended operations manually every time. Also suspended operation will not produce any error message. We can write the AFTER SUSPEND trigger to capture the suspended operations as well as error message. In AFTER SUSPEND trigger, we can write a code by using DBMS_SMTP package to notify DBA about suspended operations. We can also write the error message in log table by using autonomous transactions.

Here is the sample AFTER SUSPEND trigger skeleton.

CREATE OR REPLACE TRIGGER suspended_operations
AFTER SUSPEND
ON DATABASE
DECLARE
-- Declare any variables
BEGIN
-- Alter default timeout period.
Dbms_Resumable.Set_Timeout(3600);
-- Capture the error message into log table
-- Send email/page to DBA to make corrective action
END;
/

How do we see which operations are suspended in the database?

a) We can check the alert log
b) We can view USER_RESUMABLE or DBA_RESUMABLE

Resumable space parameters in imp/exp, SQL Loader:

We can use these below parameters to suspend the (SQL Loader, imp/exp) data load if there is space failure.

RESUMABLE suspend when a space related error is encountered(N)
RESUMABLE_NAME text string used to identify resumable statement
RESUMABLE_TIMEOUT wait time for RESUMABLE

DBMS_RESUMABLE Package: This package is created for managing resumable space. SYS user should grant execute privileges to other schema to use this package.

ABORT(sessionID) - Ends the specified suspended session. Caller must be the owner of the session with sessionID, have ALTER SYSTEM privilege, or have DBA privileges.

GET_SESSION_TIMEOUT(sessionID) - Returns the timeout period in seconds for the specified session, or -1 if the session does not exist.

SET_SESSION_TIMEOUT(sessionID, timeout) - Sets the timeout in seconds of the specified session with immediate effect.

GET_TIMEOUT() - Returns the timeout period in seconds for the current session.

SET_TIMEOUT(timeout) - Sets the timeout in seconds of the current session with immediate effect.

DBMS_RESUMABLE.SPACE_ERROR_INFO(...) - Returns information about the space error when called from within an AFTER SUSPEND trigger.

Note : We use the below command to enable or disable resumable space allocation in oracle9i.

alter session enable resumable
alter session disable resumable

But in oracle10g, we do not need to use these command to enable or disable resumable allocation. Oracle10g introduced new parameter RESUMABLE_TIMEOUT, we use this parameter to enable or disable resumable space allocation.

alter session set resumable_timeout = 0 (Disable resumable space allocation)
alter session set resumable_timeout = 60 (enable resumable space allocation)

Wednesday, May 6, 2009

Flash Back Query

Oracle9i introduced Flashback query feature. Oracle Flashback Query allows users to see a consistent view of the database as it was at a point in the past. We can use SCN or TIMESTAMP to read the past data. Oracle10g went one step further and introduced two new features on top of flashback query feature. Here are the use of flash back query feature......

1. Recover the lost data or undoing incorrect commit.
2. Comparing the current data with corresponding data in the past.

Let us talk about below three topics on this article. The below code in this thread is successfully tested in oracle10gR2.

1. Flashback query(Oracle9i feature)
2. Flashback version query(Oracle10g feature)
3. Flashback transaction query(Oracle10g feature)

Prerequisite to use Flash back query freature..

1. Automatic UNDO managment should be enabled. The following init parameter should be set.

UNDO_MANAGEMENT = AUTO
UNDO_TABLESPACE = undotablespace_name
UNDO_RETENTION = n

2. We need to grant below privilege to schema where we are using this feature. Let us assume, we are using scott schema.

grant execute on dbms_flashback to scott;

Flashback Query(Oracle9i feature)

Flashback query can be enabled or disabled by using dbms_flashback package. We can flashback by using SCN or specific time. Flashback query feature will allow users to see the data on specific time or SCN in the past.

Scenario 1

Let us use the timestamp and display the past data...

scott@orcl> ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY HH24:MI:SS';

Session altered.

scott@orcl> create table flashback as select * from user_objects
2 where rownum <6;

Table created.

scott@orcl> select object_name from flashback;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
CUSTOMERS_SEQ
DEPT
DEPT1

10:58:59 scott@orcl> update flashback set object_name=lower(object_name);

5 rows updated.

10:59:14 scott@orcl> commit;

Commit complete.

10:59:17 scott@orcl> select object_name from flashback;

OBJECT_NAME
--------------------------------------------------------------------------------
auditlog
audit_seq
customers_seq
dept
dept1

scott@orcl> SELECT OBJECT_NAME from flashback AS OF
2 TIMESTAMP TO_TIMESTAMP('06-MAY-2009 10:58:26');

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
CUSTOMERS_SEQ
DEPT
DEPT1

scott@orcl>

Scenario 2

Recovering data based on specific SCN in the past...

scott@orcl> select current_scn from v$database;

CURRENT_SCN
-----------
19215382

scott@orcl> create table flashback as select * from user_objects
2 where rownum <6;

Table created.

scott@orcl> select current_scn from v$database;

CURRENT_SCN
-----------
19215408

scott@orcl> select * from flashback;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
BIN$IDl5ashFQMqE8ctrWU8K8Q==$0
BIN$dld0GhwqRlO4sMnrYyAKgQ==$0
CUSTOMERS_SEQ

scott@orcl> update flashback set object_name=lower(object_name);

5 rows updated.

scott@orcl> commit;

Commit complete.

scott@orcl> select * from flashback as of scn 19215382;
select * from flashback as of scn 19215382
*
ERROR at line 1:
ORA-01466: unable to read data - table definition has changed

scott@orcl> select * from flashback as of scn 19215408;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
BIN$IDl5ashFQMqE8ctrWU8K8Q==$0
BIN$dld0GhwqRlO4sMnrYyAKgQ==$0
CUSTOMERS_SEQ

scott@orcl> select * from flashback;

OBJECT_NAME
--------------------------------------------------------------------------------
auditlog
audit_seq
bin$idl5ashfqmqe8ctrwu8k8q==$0
bin$dld0ghwqrlo4smnryyakgq==$0
customers_seq

scott@orcl>

Note : when we enable flashback query, we provide either a timestamp or SCN. Timestamp is mapped to an SCN number every five minutes, the SCN offers a much finer level of precision for flashback.

Scenario 3

We can use the explicit cursor to read the past data by using flashback query feature.

scott@orcl> create table flashback as select * from user_objects
2 where rownum <11;

Table created.

scott@orcl> SELECT current_scn, TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') FROM v$database;

CURRENT_SCN
-----------
TO_CHAR(SYSTIMESTAMP,'YYYY-MM-
---------------------------------------------------------------------------
19218732
2009-05-06 12:15:58

scott@orcl>

11:36:52 scott@orcl> delete flashback;

10 rows deleted.

11:37:10 scott@orcl> commit;

Commit complete.

11:37:11 scott@orcl>

I deleted the flashback table around 11.37AM. Now i wanted to revert the data through PLSQL cursor by using SCN or TIMESTAMP.

The below example reading through Timestamp.

scott@orcl> declare
cursor c1 is select * from flashback;
emprec c1%rowtype;
begin
dbms_flashback.enable_at_time('06-MAY-2009 11:36:52');
OPEN C1;
DBMS_FLASHBACK.DISABLE;
LOOP
FETCH c1 into emprec;
exit when c1%notfound;
insert into flashback(OBJECT_NAME)
values(emprec.object_name);
end loop;
close c1;
commit;
end;
/

PL/SQL procedure successfully completed.

scott@orcl> SELECT * FROM FLASHBACK;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
BIN$EkjOJm2AS66HXzkrAueJiA==$0
BIN$IDl5ashFQMqE8ctrWU8K8Q==$0
BIN$YUw9dPZ5SueBF5RDCMLJIQ==$0
BIN$dld0GhwqRlO4sMnrYyAKgQ==$0
CUSTOMERS_SEQ
DEPT
DEPT1
DO_SOMETHING

10 rows selected.

scott@orcl>

The below example reading flashback data through SCN.

scott@orcl> declare
cursor c1 is select * from flashback;
emprec c1%rowtype;
begin
dbms_flashback.Enable_At_System_Change_Number(19218732);
OPEN C1;
DBMS_FLASHBACK.DISABLE;
LOOP
FETCH c1 into emprec;
exit when c1%notfound;
insert into flashback(OBJECT_NAME)
values(emprec.object_name);
end loop;
close c1;
commit;
end;
/

PL/SQL procedure successfully completed.

scott@orcl> select * from flashback;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
BIN$EkjOJm2AS66HXzkrAueJiA==$0
BIN$IDl5ashFQMqE8ctrWU8K8Q==$0
BIN$YUw9dPZ5SueBF5RDCMLJIQ==$0
BIN$dld0GhwqRlO4sMnrYyAKgQ==$0
CUSTOMERS_SEQ
DEPT
DEPT1
DO_SOMETHING

10 rows selected.

scott@orcl>

Note: We can not do any operation in the database when database is in Flashback mode.

scott@orcl> declare
cursor c1 is select * from flashback;
emprec c1%rowtype;
begin
dbms_flashback.Enable_At_System_Change_Number(19218732);
OPEN C1;
--DBMS_FLASHBACK.DISABLE;
LOOP
FETCH c1 into emprec;
exit when c1%notfound;
insert into flashback(OBJECT_NAME)
values(emprec.object_name);
end loop;
close c1;
commit;
end;
/
declare
*
ERROR at line 1:
ORA-08182: operation not supported while in Flashback mode
ORA-06512: at line 11

So far, we have seen oracle9i features. Oracle9i has ability to read the past data by using SCN or timestamp. But oracle10g has gone one step further and has ability to read the past data for specific time window. This feature is called as flashback version query. Also oracle10g can get extra information about the transactions listed by flashback version queries.

As a summary, oracle10g introduced two new features on top of flashback query (which is introduced in oracle9i).

1. Flashback version query
2. Flashback transaction query

Flashback Version query (Oracle10g feature)
Flashback version query display the past data on specific time window. This feature helps to find the detail level data changes during that window. Here i created table and apply three transaction. At the end, we are able to display all the changes made by the transaction during that time period.

scott@orcl> create table flashversion(name varchar2(20));

Table created.
scott@orcl> SELECT TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') FROM v$database;

TO_CHAR(SYSTIMESTAMP,'YYYY-MM-
---------------------------------------------------------------------------
2009-05-08 09:07:59

scott@orcl> insert into flashversion values('SCOTT');

1 row created.

scott@orcl> commit;

Commit complete.

scott@orcl> update flashversion set name='MANI';

1 row updated.

scott@orcl> commit;

Commit complete.

scott@orcl> update flashversion set name='JANI';

1 row updated.

scott@orcl> commit;

Commit complete.

scott@orcl> SELECT TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') FROM v$database;

TO_CHAR(SYSTIMESTAMP,'YYYY-MM-
---------------------------------------------------------------------------
2009-05-08 09:09:22

scott@orcl> SELECT versions_starttime,
2 name
3 FROM flashversion
4 VERSIONS BETWEEN TIMESTAMP TO_TIMESTAMP('2009-05-08 09:07:59', 'YYYY-MM-DD HH24:MI:SS')
5 AND TO_TIMESTAMP('2009-05-08 09:09:22', 'YYYY-MM-DD HH24:MI:SS');

VERSIONS_STARTTIME
---------------------------------------------------------------------------
NAME
--------------------
08-MAY-09 09.09.15 AM
JANI

08-MAY-09 09.08.41 AM
MANI

08-MAY-09 09.08.07 AM
SCOTT


We can use the below flashback pseudo columns with above query.

VERSIONS_STARTSCN => Starting SCN when row took on this value
VERSIONS_STARTTIME => Starting TIMESTAMP when row took on this value

Note : The value of NULL is returned if the row was created before the lower bound SCN or TIMESTAMP.

VERSIONS_ENDSCN => Ending SCN when row last contained this value
VERSIONS_ENDTIME => Ending TIMESTAMP when row last contained this value

Note : The value of NULL is returned if the value of the row is still current at the upper bound SCN or TIMESTAMP.

VERSIONS_XID => ID of the transaction that created the row in it's current state.
VERSIONS_OPERATION => Operation performed by the transaction ((I)nsert, (U)pdate or (D)elete)

Here is the query with all the pseudo column

SELECT
versions_startscn,
versions_starttime,
versions_endscn,
versions_endtime,
versions_xid,
versions_operation,
name
FROM flashversion
VERSIONS BETWEEN
TIMESTAMP TO_TIMESTAMP('2009-05-08 09:07:59', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2009-05-08 09:09:22', 'YYYY-MM-DD HH24:MI:SS');
/

Flashback Transaction Query(Oracle10g feature)

Flashback transaction query can be used to get extra information about the transactions listed by flashback version queries. The VERSIONS_XID column values from a flashback version query can be used to query the FLASHBACK_TRANSACTION_QUERY view like:

scott@orcl> SELECT versions_xid,name
2 name
3 FROM flashversion
4 VERSIONS BETWEEN
5 TIMESTAMP TO_TIMESTAMP('2009-05-08 09:07:59', 'YYYY-MM-DD HH24:MI:SS')
6 AND TO_TIMESTAMP('2009-05-08 09:09:22', 'YYYY-MM-DD HH24:MI:SS');

VERSIONS_XID NAME
---------------- --------------------
010010007B0D0000 JANI
030028003A110000 MANI
01002E007B0D0000 SCOTT

scott@orcl> connect sys/password@orcl as sysdba
Connected.
sys@orcl> SELECT undo_sql
2 FROM flashback_transaction_query
3 WHERE xid = HEXTORAW('010010007B0D0000');

UNDO_SQL
--------------------------------------------------------------------------------
update "SCOTT"."FLASHVERSION" set "NAME" = 'MANI' where ROWID = 'AAANPLAAEAAAGOlAAA';

sys@orcl> SELECT undo_sql
2 FROM flashback_transaction_query
3 WHERE xid = HEXTORAW('030028003A110000');

UNDO_SQL
--------------------------------------------------------------------------------
update "SCOTT"."FLASHVERSION" set "NAME" = 'SCOTT' where ROWID = 'AAANPLAAEAAAGOlAAA';

Flashback_transaction_query is a view which is belonging to sys schema. If you need to access from different schema, then you need to grant necessary privileges to other schema.

Here is the query content for flashback_transaction_query view.

CREATE OR REPLACE FORCE VIEW SYS.FLASHBACK_TRANSACTION_QUERY
(XID,
START_SCN,
START_TIMESTAMP,
COMMIT_SCN,
COMMIT_TIMESTAMP,
LOGON_USER,
UNDO_CHANGE#,
OPERATION,
TABLE_NAME,
TABLE_OWNER,
ROW_ID,
UNDO_SQL
)
AS
SELECT xid,
start_scn,
start_timestamp,
DECODE (commit_scn,
0, commit_scn,
281474976710655, NULL,
commit_scn)
commit_scn,
commit_timestamp,
logon_user,
undo_change#,
operation,
table_name,
table_owner,
row_id,
undo_sql
FROM sys.x$ktuqqry;

Monday, May 4, 2009

Recyclebin

Flashback drop table is one of the awesome feature in oracle10g. Flashback query feature was introduced in oracle9i and we were able to read the past data by using timestamp or SCN for existing table in database. Oracle9i flashback query does not have the ability to recover the dropped tables. But oracle10g introduced a flashback drop feature to recover the dropped tables.

Oracle10g introduced recyclebin to keep the dropped tables for longer time subject to space.

When recyclebin is enabled, any table you drop will not get dropped. Instead, it will rename the dropped tables and dependent object to system generated name that starts with BIN$.

Recyclebin is a logical structure within each tablespace that holds dropped tables and dependent object to that table. Dependent objects are index, triggers, constraints, LOB segments, nested_tables etc. The space associated with the dropped table is not immediately available, but shows up the DBA_FREE_SPACE. Free space in the tablespace that is not occupied by dropped tables. When space pressure occurs in the tablespace, objects in the recyclebin are deleted in First-in first-out(FIFO) fashion.

The dropped object still belongs to the owner and still counts againts the quota for the owner in the tablespace.

As long as a tablespace has no space pressure, dropped objects are available indefinitely for recovery. Dropped objects are removed automatically when there is a space pressure. Also dropped objects can be removed manually by PURGE command.

This article is tested on Oracle10g version.

Let us test the recyclebin features as multiple scenario.
Scenario 1

Here table is created with dependent objects(index, primary key, trigger, constraints, LOB segments, nested_tables etc). Let us drop the table and recover using recyclebin. When we recover this table, the dependent objects are also recovered. But the dependent object names never changed to original names.

scott@orcl> create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> alter table flashdrop
2 add primary key(table_name);

Table altered.

scott@orcl> create index idxx on flashdrop(tablespace_name);

Index created.

scott@orcl> create trigger trg_flashdrop
2 before insert on flashdrop
3 for each row
4 begin
5 null;
6 end;
7 /

Trigger created.

scott@orcl> select count(*) from flashdrop;

COUNT(*)
----------
5

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl> show recyclebin
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------- ------------------------------ ------------ -------------------
FLASHDROP BIN$jmJpbe5kSqOynybZkA+yfg==$0 TABLE 2009-05-04:18:37:20


scott@orcl> select object_name,original_name from recyclebin;

OBJECT_NAME ORIGINAL_NAME
------------------------------ --------------------------------
BIN$WcPD/4MlRLayVzQi3x/Vzw==$0 SYS_C005982
BIN$gXTgHi0nQPidAxbnCx5b+w==$0 TRG_FLASHDROP
BIN$jmJpbe5kSqOynybZkA+yfg==$0 FLASHDROP
BIN$4sBW2ND1RYmDYs3JerZodA==$0 IDXX

scott@orcl> flashback table flashdrop to before drop;

Flashback complete.

scott@orcl> select count(*) from flashdrop;

COUNT(*)
----------
5

scott@orcl> show recyclebin

scott@orcl> select object_name,original_name from recyclebin;

no rows selected

scott@orcl> select constraint_name from
2 user_constraints where table_name='FLASHDROP';

CONSTRAINT_NAME
------------------------------
BIN$OIrKaH31R+WaqLWxgMWBQw==$0
BIN$lWD5jjLRQjacvAJJN6i0pQ==$0

scott@orcl> select trigger_name from user_triggers
2 where table_name='FLASHDROP';

TRIGGER_NAME
------------------------------
BIN$gXTgHi0nQPidAxbnCx5b+w==$0

scott@orcl> select index_name from user_indexes
2 where table_name='FLASHDROP';

INDEX_NAME
------------------------------
BIN$WcPD/4MlRLayVzQi3x/Vzw==$0
BIN$4sBW2ND1RYmDYs3JerZodA==$0

Scenario 2

Tables can be dropped and recovered with different name.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> select count(*) from flashdrop;

COUNT(*)
----------
5

scott@orcl>

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl> flashback table flashdrop to before drop
2 rename to old_flashdrop;

Flashback complete.

scott@orcl> select count(*) from flashdrop;
select count(*) from flashdrop
*
ERROR at line 1:
ORA-00942: table or view does not exist

scott@orcl> select count(*) from old_flashdrop;

COUNT(*)
----------
5

Scenario 3

The recyclebin may contain several versions of a dropped object. Oracle restores them in LIFO order. It restores most recent version of dropped object. We can restore older versions by repeatedly restoring until you get the version you want, or by using the correct version's BIN$... name directly.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl> select object_name, original_name,droptime
2 from recyclebin;

OBJECT_NAME ORIGINAL_NAME DROPTIME
------------------------------ -------------------------------- -------------------
BIN$QZwwUzhJQT2GZM/PIEW3pA==$0 FLASHDROP 2009-05-05:10:06:00
BIN$GR72mxnyQp+++qxOmVGQfg==$0 FLASHDROP 2009-05-05:10:05:25
BIN$ePj5BAIxTuuZy4oRO3d/oA==$0 FLASHDROP 2009-05-05:10:05:36

scott@orcl>

scott@orcl> flashback table flashdrop to before drop;

Flashback complete.

scott@orcl> select object_name, original_name,droptime
2 from recyclebin;

OBJECT_NAME ORIGINAL_NAME DROPTIME
------------------------------ -------------------------------- -------------------
BIN$GR72mxnyQp+++qxOmVGQfg==$0 FLASHDROP 2009-05-05:10:05:25
BIN$ePj5BAIxTuuZy4oRO3d/oA==$0 FLASHDROP 2009-05-05:10:05:36

scott@orcl>

In this scenario, Oracle recovered the table which is dropped recently.

Scenario 4

Recyclebin feature is enabled by default in oracle10g. But after turning the recyclebin feature off, we can recover the tables which are already existing in recyclebin.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> drop table flashdrop;

Table dropped.

scott@orcl> show recyclebin
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------- ------------------------------ ------------ -------------------
FLASHDROP BIN$WXrd4IW+SKmYh9EGU8bg5Q==$0 TABLE 2009-05-05:10:24:59

scott@orcl> ALTER SESSION SET recyclebin = OFF;

Session altered.

scott@orcl> flashback table flashdrop to before drop;

Flashback complete.

scott@orcl> show recyclebin;


scott@orcl> select count(*) from flashdrop;

COUNT(*)
----------
5

scott@orcl>

Scenario 5

Let us say, we start updating on flashdrop table at 12PM. We complete all the updates around 2PM. After we realized that, the updates went wrong and we want to revert the table back to 12PM... We can achieve this using FLASHBACK TABLE feature.

scott@orcl>create table flashdrop as
2 select * from user_tables
3 where rownum < 6;

Table created.

scott@orcl> SELECT current_scn from v$database;

CURRENT_SCN
-----------
19220251

scott@orcl> delete flashdrop where rownum < 2;

scott@orcl> commit;

Commit complete.

scott@orcl> update flashdrop set object_name=lower(object_name);

4 rows updated.

scott@orcl> select object_name from flashdrop;

OBJECT_NAME
--------------------------------------------------------------------------------
audit_seq
bin$ekjojm2as66hxzkrauejia==$0
bin$hfdops9utc2qdmy9pamg6w==$0
bin$idl5ashfqmqe8ctrwu8k8q==$0

scott@orcl> flashback table flashdrop to scn 19220251;
flashback table flashdrop to scn 19220251
*
ERROR at line 1:
ORA-08189: cannot flashback the table because row movement is not enabled


scott@orcl> alter table flashdrop enable row movement;

Table altered.

scott@orcl> flashback table flashdrop to scn 19220251;

Flashback complete.

scott@orcl> select object_name from flashdrop;

OBJECT_NAME
--------------------------------------------------------------------------------
AUDITLOG
AUDIT_SEQ
BIN$EkjOJm2AS66HXzkrAueJiA==$0
BIN$HFDoPs9uTC2QdMY9pAMG6w==$0
BIN$IDl5ashFQMqE8ctrWU8K8Q==$0

scott@orcl>

Flashback of table can also be performed using timestamps as below...

FLASHBACK TABLE flashdrop TO TIMESTAMP TO_TIMESTAMP('2004-05-06 10:00:00', 'YYYY-MM-DD HH:MI:SS');


How do we purge objects manully in recyclebin?

PURGE TABLE tablename; -- Specific table.
PURGE INDEX indexname; -- Specific index.
PURGE TABLESPACE ts_name; -- All tables in a specific tablespace.
PURGE TABLESPACE ts_name USER username; -- All tables in a specific tablespace for a specific user.
PURGE RECYCLEBIN; -- The current users entire recycle bin.
PURGE DBA_RECYCLEBIN; -- The whole recycle bin.

How do we bypass the recyclebin?

We can add PURGE statement with drop table command to bypass the recyclebin. The tables will be dropped without going into recycle bin. But when we drop tablespace(DROP TABLESPACE .... INCLUDING CONTENTS), tablespace is not placed in recyclebin. It drops associated recyclebin for that tablespace.

scott@orcl> DROP TABLE EMPTABLE PURGE;

Table dropped.

scott@orcl> FLASHBACK table emptable to before drop;
FLASHBACK table emptable to before drop
*
ERROR at line 1:
ORA-38305: object not in RECYCLE BIN

scott@orcl>

Naming convention for object in recyclebin:

When we drop the object, the dropped objects are renamed and moved to recyclebin. The names are globally unique and are used to identify the objects while they are in the recycle bin. The recyclebin name of an object is always 30 characters long. Dropped Object names are formed as follows: BIN$$globalUID$version

globalUID is a globally unique, 24 character long identifier generated for the object.
version is a version number assigned by the database.

Limitations on Recyclebin:

1. Only non system locally managed tablespace(LMT) can have a recycle bin. However, dependent objects in a dictionary managed tablespace are protected if the dropped object is LMT.

2. All dependent objects will be placed in recyclebin except bitmap join index, FK constraints, Materialized view logs)

3. Indexes are protected only if the table is dropped first. Explicitly dropping an index does not place in recyclebin.

4. There is no fixed amount of space allocated to the recycle bin, and no guarantee as to how long dropped objects remain in the recycle bin. Depending upon system activity, a dropped object may remain in the recycle bin for seconds, or for months.

5. Due to security concerns, tables which have Fine-Grained Auditing (FGA) and Virtual Private Database (VPD) policies defined over them are not protected by the recycle bin.

6. Partitioned index-organized tables are not protected by the recycle bin.

Recyclebin Views:

We have two views, USER_RECYCLEBIN, DBA_RECYCLEBIN. For our convenience, synonym RECYCLEBIN is created which is pointing to user_recyclebin.

How do we disable the recyclebin?

The recyclebin feature is enabled in oracle10g by default. We can change the initialization parameter RECYCLEBIN to enable or disable this feature.

ALTER SESSION SET recyclebin = OFF;
ALTER SYSTEM SET recyclebin = OFF;

Monday, April 20, 2009

SQL Loader Memory Parameters

There are few command line SQLLoader parameters which are used for tuning direct data load. These parameters should be tuned only when we have any performance issue for loading the data through SQLLoader. Since these parameters are directly impacting client memory... This article is written in Oracle10g and these parameter might change in future Oracle Versions...

Here are the below parameters which are used only for Direct Path Data load.....

READSIZE is size of the buffer used to read the data from input data file. The default size is 1MB(1048576 bytes).

COLUMNARRAYROWS is number of rows in a two-dimensional array used to hold field information. This holds field information for every row. The default is 5000 rows.

STREAMSIZE is size of the buffer to send the data to server for loading into target table. The default is 256000 bytes.

MULTITHREADING is an option that allows concurrent execution of some SQL*Loader client operations with database server data loading. If multithreading is turned off, the SQL*Loader client will always wait until the server finishes a data load before continuing. If multithreading is turned on, some calls to the server will be executed by the client's "load thread" while the client's "main thread" continues converting data and building stream buffers.

When the MULTITHREADING command-line parameter is set to TRUE (the default on multi-CPU clients), SQL*Loader will overlap stream loading with stream conversion. If the main thread has converted data from a column array into a stream and the stream is filled before all data in the column array has been processed, the load thread will load that stream while the main thread continues to convert the column array into another stream buffer.

DATE_CACHE used in direct path load. This parameter will play a role when we load the date data from input file into Oracle table. When we have date value in input file, sqlloader has to convert the date string into Oracle DATE Format before load into target table. When we have large duplicate date string in input file, then sqlloader keeps the converted date value in date_cache first time and reuse every occurrence of the same date string in input file. So it would save time for date conversion when we have the same date string in the input file.

If you know the number of duplicate date strings is small or the number of unique date strings is very large, then you can disable the date cache by specifying DATE_CACHE=0 on the command line. The default value for DATE_CACHE is 1000. If number of unique date values in table greater then the size of the date cache, then DATE_CACHE will be disabled. All the date columns will share the same DATE_CACHE.

Please click this link if you need more info about DATE_CACHE.

Here is the process flow between these three memory parameters(READSIZE, COLUMNARRAYROWS and STREAMSIZE) for DIRECT Path data load...

Step1

SQLLoader reads data from input data file and load into memory buffer. This buffer size is controlled by READSIZE parameter.

Step2

SQLLoader parse every logical record from step1, and isolate the fields in COLUMNARRAY memory buffer based on field definition which is specified in SQLLoader control file. This process is called as "Field setting". The number of rows in the column array is controlled by COLUMNARRAYROWS parameter.

Step3

Step2 will continue untill COLUMNARRAY buffer is full.

Step4

SQLLoader will parse the columnarray data into STREAMBUFFER. This buffer size is controlled by STREAMSIZE parameter. There may be a possibility that, STREAMBUFFER might be getting full before it copies all the data from COLUMNARRAY buffer.

Step5

STREAMBUFFER data will be sent to server.

Step6

Server will parse STREAMBUFFER data and load into target table.

Step7

Once step6 is completed, then STREAMBUFFER will be set to empty.

Step8

If more data that needs to be loaded from COLUMNARRAYBUFFER, then continue from step4. If there is no data in COLUMNARRAYBUFFER, then continue step9.

Step9

If the COLUMNARRAY buffer data is completed(loaded into target table via streambuffer), then sqlloader will look for remaining data in READBUFFER. If there are more data in READBUFFER, then continue from step2. Otherwise, continue step10

Step10

If all the records in READBUFFER is processed, then load more records from input data file into READBUFFER which is apparently from step1.

Note : If you need more info on these DIRECT Load Tuning parameters, please click this link.

Thursday, April 2, 2009

Integer Versus Number data type

What is the difference betwen INTEGER and NUMBER? When should we use NUMBER and when should we use INTEGER? I just wanted to update my comments here...

NUMBER always stores as we entered. Scale is -84 to 127. But INTEGER rounds to whole number. The scale for INTEGER is 0. INTEGER is equivalent to NUMBER(38,0). It means, INTEGER is constrained number. The decimal place will be rounded. But NUMBER is not constrained.

INTEGER(12,2) => 12
INTEGER(12.5) => 13
INTEGER(12.9) => 13
INTEGER(12.4) => 12
NUMBER(12,2) => 12.2
NUMBER(12.5) => 12.5
NUMBER(12.9) => 12.9
NUMBER(12.4) => 12.4

INTEGER is always slower then NUMBER. Since integer is a number with added constraint. It takes additional CPU cycles to enforce the constraint. I never watched any difference, but there might be a difference when we load several millions of records on the INTEGER column. If we need to ensure that the input is whole numbers, then INTEGER is best option to go. Otherwise, we can stick with NUMBER data type.

Sunday, March 29, 2009

New Enhancements in SQL* PLUS

SQL* PLUS is a tool to edit the SQL command and format the SQL output. Here is the new enhancement in SQL*PLUS for oracle10g.

Enhancement 1
Prior to oracle10g if we describe the object that is invalid, the describe command will fail with error. But in oracle10g, DESCRIBE will try to validate the object first, and if the object is still invalid after validation, it gives the error message. If the validation is successful, then DESCRIBE command will also be successful.
Let us test this in oracle 10g & oracle9i and see the difference....

Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options

scott@orcl> create or replace procedure testproc is
2 v_cnt number;
3 begin
4 select count(*) into v_cnt
5 from temptable;
6 end;
7 /

Procedure created.

scott@orcl> desc testproc;
PROCEDURE testproc
scott@orcl> drop table temptable;

Table dropped.
scott@orcl> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
INVALID
scott@orcl> create table temptable(no number);

Table created.

scott@orcl> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
INVALID

scott@orcl> desc testproc;
PROCEDURE testproc


scott@orcl> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
VALID

scott@orcl>

The above case, the procedure is recompiled when we describe the procedure...

Let us test the same scenario in oracle9i...
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production

SQL> create or replace procedure testproc is
2 v_cnt number;
3 begin
4 select count(*) into v_cnt
5 from temptable;
6 end;
7 /

Procedure created.

SQL>
SQL> desc testproc;
PROCEDURE testproc

SQL> drop table temptable;

Table dropped.

SQL>
SQL> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
INVALID

SQL> create table temptable(no number);

Table created.

SQL>
SQL> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
INVALID

SQL> desc testproc;
ERROR:
ORA-24372: invalid object for describe


SQL> select status from user_objects
2 where object_name='TESTPROC';

STATUS
-------
INVALID

SQL> alter procedure testproc compile;

Procedure altered.

SQL> desc testproc
PROCEDURE testproc

SQL>
The above case, the procedure is not recompiled when we describe the procedure...

Enhancement 2

The glogin.sql, login.sql files are profile files used to customize our SQL*Plus environment when we log in SQL*Plus. The glogin.sql file is site profile file and located in $ORACLE_HOME/sqlplus/admin directory. The login.sql file user profile and is executed after the glogin.sql file. Prior to oracle10g, this two files(glogin.sql, login.sql) are executed one after other only when we restart the SQL*Plus. But in oracle10g, these two files are executed one after other for every connect as well as every restart of SQL*Plus.

Let us test this in oracle10g... Our goal is to display username and instance name in the sql prompt. Let me add this below entry in glogin.sql file.

column global_name new_value gname
set termout off
select lower(user) '@'
INSTANCE_NAME global_name
from V$INSTANCE;
set sqlprompt '&gname> '
set termout on

Let us restart the SQL*Plus.

SQL*Plus: Release 10.1.0.2.0 - Production on Sun Mar 29 11:04:41 2009

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


Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options
scott@orcl>

Now again we will connect to another user and see SQL prompt is changing...

scott@orcl> connect training/training@orcl
Connected.
training@orcl>

so in Oracle10g, glogin.sql is executing every connect as well as every restart of SQL* Plus.

Let us test the same in oracle9i.

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production

dwadba@invent> connect sales@invent
Enter password: ************
Connected.
dwadba@invent>

so in Oracle9i, glogin.sql is not executing for every connect. It executes only when we start the SQL*Plus.

Enhancement 3

oracle10g supports white space in filenames when we use commands like SPOOL, SAVE, RUN.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options

scott@orcl> spool 'c:/test file.txt';
scott@orcl> select sysdate from dual;

SYSDATE
---------
29-MAR-09

scott@orcl> spool off

In oracle9i, it does not support space for filenames...

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production

SQL> spool 'c:/test file.txt';
SP2-0333: Illegal spool file name: "'c:/test file.txt'" (bad character: ' ')

Enhancement 4

The spool command stores query result in a file. In oracle10g, SPOOL command includes the APPEND extension to add the contents of the buffer to the end of the file.

Let us test this in oracle10g.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options

scott@orcl> spool c:/test.txt
scott@orcl> select sysdate from dual;

SYSDATE
---------
29-MAR-09

scott@orcl> spool off
scott@orcl> spool c:/test.txt append
scott@orcl> select sysdate from dual;

SYSDATE
---------
29-MAR-09

scott@orcl> spool off
scott@orcl>

Let us test the same in oracle9i.

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production

SQL> spool c:/test.txt
SQL> select sysdate from dual;

SYSDATE
---------
30-MAR-09

SQL> spool off
SQL> spool c:/test.txt append
SP2-0333: Illegal spool file name: "c:/test.txt append" (bad character: ' ')

Friday, February 20, 2009

Character and Byte Semantics in Oracle

Historically Oracle character data type column have been defined by using number of bytes. This is good as long as total number of characters equal to total number of bytes. When we maintain multilingual version of application, the database needs to set as a multi byte character set. For instance, the column data type length is VARCHAR2(10). In this case, we can store 10 characters for single byte character set. When we moved to multi byte character set, we can not store 10 characters. Oracle9i has solved this problem with the introduction of character and byte length semantics. Oracle9i introduced NLS_LENGTH_SEMANTICS init parameter to solve this issue. NLS_LENGTH_SEMANTICS enables you to create CHAR and VARCHAR2 columns using either byte or character length semantics.

There are three different ways, we can declare CHAR/VARCHAR2 data type.
Let us take VARCHAR2(10) as an example here.

1. VARCHAR2(10)
2. VARCHAR2(10 BYTE)
3. VARCHAR2(10 CHAR)

What is the difference between VARCHAR2(10), VARCHAR2(10 BYTE) & VARCHAR2(10 CHAR).

VARCHAR2(10 BYTE)

When we declare the data type as VARCHAR2(10 BYTE), oracle stores only 10 bytes of data, regardless of how many characters this represents. This is perfect when the database has only single byte character set. Since total number of charater is equal to total number of bytes.. So this case, oracle stores 10 Characters.. But when database handles multilingual version of application, then oracle stores multi byte characters. In this case, oracle can store only 5 character.

VARCHAR2(10 CHAR)

This allows the specified number of characters to be stored in the column regardless of number of bytes this equates to.. Oracle can store 10 character regardless of single byte character set or multi byte character set.

VARCHAR2(10)

Oracle stores 10 Character or 10 Bytes depends on NLS_LENGTH_SEMANTICS parameter value. if it sets to BYTE, then we can store 10 bytes(if it is mutibyte character set, then we can store 5 characters). The default value is BYTE. When this parameter is CHAR, then we can store 10 characters regardless of single byte character set or multi byte character set. When we move the database to multibyte characterset, we can change NLS_LENGTH_SEMANTICS paramter to CHAR to resolve the storage issue. Existing columns will not be affected when we change the value for this parameter.

The default character semantics of the database or session can be altered using the NLS_LENGTH_SEMANTICS parameter like:

SQL> alter system set nls_length_semantics=char;

System altered.

SQL> alter system set nls_length_semantics=byte;

System altered.

SQL> alter session set nls_length_semantics=char;

Session altered.

SQL> alter session set nls_length_semantics=byte;

Session altered.

Note : NLS_LENGTH_SEMANTICS does not apply to tables in SYS and SYSTEM. The data dictionary always uses byte semantics.