Anda di halaman 1dari 18

Advanced features of Oracle 11g

23/02/2010

Thiyagarajan Raghavan
Thiyagarajan.ragahvan@tcs.com
List of Topics
1. DDL WAIT OPTION
2. VIRTUAL COLUMNS
3. INVISIBLE INDEXES
4. READ ONLY TABLES
5. CONTINUE CLAUSE
6. STRAIGHT SEQUENCES
7. COMPOUND TRIGGERS
8. NEW PARTITIONING TECHNIQUES

TCS Public
1. DDL WAIT OPTION

• Oracle automatically places DML locks on tables when some of their rows are
being modified by any transaction. Lock type for these will be ‘TX’ in V$LOCK
table).
• In addition to the DML locks, such a transaction will also hold a table level DDL
lock, preventing other transactions from altering or dropping the table until the
ongoing DML transaction is completed. Lock type for this will be ‘TM’ in V$LOCK
table).

• Prior to the introduction of Oracle 11g, DDL lock request won’t wait for a DML lock.
It will automatically fail throwing the following error.

Alter table sales add (tax_code varchar2 (10))

ERROR at line 1:

ORA-00054: resource busy and acquire with NOWAIT specified or timeout


expired.

• In oracle 11g,we can use ddl_lock_timeout parameter to specify the duration for
which a DDL statement will wait for DML lock

SQL>alter session set ddl_lock_timeout=100;

• Here it will not error out. Instead, it will wait for 100 seconds. In that 100 seconds,
it continually re-tries the DDL operation until it’s successful or the time expires,
whichever comes first.

TCS Public
2. VIRTUAL COLUMNS

• A virtual column is a column that is derived by evaluating an expression based on


one or more of the actual columns or by evaluating a SQL or PL/SQL function.

• Unlike normal columns, the virtual column data is not stored permanently on
disk. The database computes its value when you query it, by dynamically
evaluating the expression on other columns.

LIMITATIONS:

• Can’t create virtual columns on IOT, external table, temporary table or a cluster.
• Its data type can’t be LOB, RAW or a user defined type.
• All columns in the column expression must belong to same table.
• You can’t update a virtual column by using it in the SET clause of an update
statement.

Example:

Create table emp (empno number(5),


sal number(7,2),
hrly_rate number(7,2) generated always as (sal/2080));

TCS Public
3. INVISIBLE INDEXES

• Prior to Oracle 11g, the optimizer will be able to see all the indexes that are
created.

• However in Oracle 11g, we can create invisible indexes that are not seen by
optimizer, hence it won’t be taken into account when the optimizer created the
execution plan for the statement.

• You can use this as a temporary index, for testing the use of an index before
making it ‘official ’.
• You can also use it as an alternative to dropping the indexes or making them
unusable.
• You can use it to test the effects of dropping the index.

SQL>create index test_idx on test(tname) tablespace testdat invisible;

SQL> alter index test_idx2 invisible;

SQL> alter index test_idx2 visible;

• Also you can make all the invisible indexes visible to optimizer again by
setting the optimizer_use_invisible_indexes parameter to TRUE either at
session level or system level

SQL> ALTER SESSION SET


OPTIMIZER_USE_INVISIBLE_INDEXES=TRUE;

TCS Public
4. READ ONLY TABLES

• In Oracle 11g you can make a table read only, which means the database will not
permit you to add, remove or alter the data in any way.

• For example, if you have a configuration file that you want to keep safe from any
changes by any users.

SQL > alter table test read only;

• You won’t be permitted to perform the following operations on read-only tables.


™ truncate table
™ select for update,
™ any DML operation
™ alter table drop/truncate/exchange partition,
™ flashback table
• You can perform the following operations on a read-only table.
Syntax:

select
create|alter|drop index
alter table add|modify|drop|enable|diasble,constraint
rename table and alter table rename to
drop table

• You can return a table to the normal read-write status by specifying the READ
WRITE clause in the ALTER TABLE statement as shown below.

SQL> alter table test read write;

TCS Public
5. CONTINUE CLAUSE

• With all its power, until now PL/SQL was missing one important piece of grammar:
how to instruct it to do nothing, go to the end of the loop, and loop again.

• In Oracle Database 11g PL/SQL has a new construct called CONTINUE, which is
used in a loop. The statement moves the logic to the end of the loop and then to
the beginning of the loop. Here is a small example that shows how the control
moves to the end of the loop when the counter is not a multiple of 10.

Example:

begin
for ctr in 1..100 loop
continue when mod(ctr,10) != 0;
dbms_output.put_line (‘ctr=’||ctr);
end loop;
end;
/

Here is the output:


ctr=10
ctr=20
ctr=30
…...

TCS Public
6. STRAIGHT SEQUENCES

• When you had to use a sequence in a PL/SQL program earlier, you had to use a
construct like

SELECT <Seq>. NEXTVAL INTO <VariableName> FROM DUAL prior to this release.

declare

trans_id number(10);

begin

select myseq.nextval into trans_id from dual;

end;

• Not anymore. You can directly assign the next value of a sequence to a variable:

declare

trans_id number(10);

begin

trans_id := myseq.nextval;

end;

TCS Public
8. COMPUND TRIGGERS

• A compound trigger allows code for one or more timing points for a specific object
to be combined into a single trigger.
• The individual timing points can share a single global declaration section, whose
state is maintained for the lifetime of the statement. Once a statement ends, due to
successful completion or an error, the trigger state is cleaned up. In previous
releases this type of functionality was only possible by defining
• multiple triggers whose code and global variables were defined in a separate
package, as shown in the Mutating Table Exceptions article, but the compound
trigger allows for a much tidier solution.

• The triggering actions are defined in the same way as any other DML trigger, with
the addition of the COMPOUND TRIGGER clause. The main body of the trigger is
made up of an optional global declaration section and one or more timing point
sections, each of which may contain a local declaration section whose state is not
maintained.

TCS Public
Syntax:

CREATE OR REPLACE TRIGGER <trigger-name>


FOR <trigger-action> ON <table-name>
COMPOUND TRIGGER

-- Global declaration.
g_global_variable VARCHAR2(10);

BEFORE STATEMENT IS
BEGIN
NULL; -- Do something here.
END BEFORE STATEMENT;

BEFORE EACH ROW IS


BEGIN
NULL; -- Do something here.
END BEFORE EACH ROW;

AFTER EACH ROW IS


BEGIN
NULL; -- Do something here.
END AFTER EACH ROW;

AFTER STATEMENT IS
BEGIN
NULL; -- Do something here.
END AFTER STATEMENT;

END <trigger-name>;
/

TCS Public
Example:

ƒ Consider a hotel database: bookings for the hotel rooms are recorded in the table
named BOOKINGS. You also want to record the changes to this table to a tracking
table-sort of like auditing, but with a twist: You want to make it transactional.
Triggers are perfect for that. You come up with a small after-update row trigger
that records the old and new values along with who changed it into a table
BOOKINGS_HIST. So far, so good.
ƒ But there is a little issue here. The after-update row trigger fires for every row, and
some bookings are changed in bulk, updating hundreds of rows in one
transaction. Separate after-update-row triggers fire for each of these rows and
each execution inserts a record into the bookings_hist table, so performance is not
optimal.
ƒ A better approach may be to batch these inserts and insert them in bulk to the
bookings_hist table as well. You can accomplish that using a complex series of
triggers. The trick is to put the values to be placed in the bookings_hist table in a
collection in the row trigger and then load the data from the collection to the
bookings_hist table in the after-update-statement trigger, which fires only once.
ƒ As the actual insert happens only once, the process is faster than inserting on each
row. But these are two different triggers in separate pieces of code.
ƒ The only way to pass a collection variable from one trigger to the other is to create
a package with a collection variable such as VARRAY or PL/SQL TABLE in the
package specification, populate it on the after-update row trigger, and read in the
after-statement trigger-no easy task. Instead, wouldn’t it be simpler if you could
place all the triggers in one piece of code?
In Oracle Database 11g you can, using compound triggers. A compound trigger is
actually four different triggers defined as one. For instance, an UPDATE compound
trigger has a before statement, before row, after statement, and after row all rolled into
one compound trigger. This a single piece of code, so you can pass variables just like
any other monolithic PL/SQL code.

Compound Trigger Code:


create or replace trigger tr_bookings_track
for update of booking_dt
on bookings
compound trigger
type ty_bookings_hist is table of bookings_hist%rowtype
index by pls_integer;

TCS Public
coll_bookings_hist ty_bookings_hist;
ctr pls_integer := 0;
before statement is
begin
dbms_output.put_line(‘In before statement’);
end before statement;
before each row is
begin
dbms_output.put_line(‘In before each row’);
end before each row;
after each row is
begin
ctr := ctr + 1;
dbms_output.put_line(‘In after each row. booking_id=’||:new.booking_id);
coll_bookings_hist(ctr).booking_id := :new.booking_id;
coll_bookings_hist(ctr).mod_dt := sysdate;
coll_bookings_hist(ctr).mod_user := user;
coll_bookings_hist(ctr).old_booking_dt := :old.booking_dt;
coll_bookings_hist(ctr).new_booking_dt := :new.booking_dt;
end after each row;
after statement is
begin
dbms_output.put_line(‘In before statement’);
end before statement;
before each row is
begin
dbms_output.put_line(‘In before each row’);
end before each row;
after each row is
begin
ctr := ctr + 1;

TCS Public
dbms_output.put_line(‘In after each row. booking_id=’||:new.booking_id);
coll_bookings_hist(ctr).booking_id := :new.booking_id;
coll_bookings_hist(ctr).mod_dt := sysdate;
coll_bookings_hist(ctr).mod_user := user;
coll_bookings_hist(ctr).old_booking_dt := :old.booking_dt;
coll_bookings_hist(ctr).new_booking_dt := :new.booking_dt;
end after each row;
after statement is
begin
dbms_output.put_line(‘In after statement’);
forall counter in 1..coll_bookings_hist.count()
insert into bookings_hist
values coll_bookings_hist(counter);
end after statement;
end tr_bookings_track;
/

TCS Public
9. NEW PARTITIONING TECHNIQUES

Extended Composite partitioning:


Composite partitioning was first introduced in Oracle 8i where you could sub
partition a RANGE partitioned table via HASH sub partitioning.
In Oracle9i, composite partitioning was expanded to include RANGE-LIST.
In Oracle 11g, you can create the following types of composite partitions
™ Range-range
™ Range-hash
™ Range-list
™ List-range
™ List-hash
™ List-list

TCS Public
Reference Partitioning
Here is a typical problem in designing partitioning schemes: not all the tables have
the same columns on which you need to partition. Suppose you are creating a sales
system with two simple tables, sales and customers:
create table customers
(
cust_id number primary key,
cust_name varchar2(200),
rating varchar2(1) not null
)
partition by list (rating)
(
partition pA values (‘A’),
partition pB values (‘B’)
);

The table sales is created as shown below. This is a child table of the customers table.
create table sales
(
sales_id number primary key,
cust_id number not null,
sales_amt number,
constraint fk_sales_01
foreign key (cust_id)
references customers
);

Ideally, you would want to partition the table sales in the same manner as table
customers: list partitioned on the column rating. But there is a serious problem: table
sales does not have a column called rating! So how do you partition it on a non-
existent column?

TCS Public
In Oracle Database 11g you can, using a new feature called Reference Partitioning. Here is
an example to show how you can apply it to the sales table:
create table sales
(
sales_id number primary key,
cust_id number not null,
sales_amt number,
constraint fk_sales_01
foreign key (cust_id)
references customers
)
partition by reference (fk_sales_01);
This creates partitions identical to those in the parent table, customers. Note that
there is no column called rating, yet the table has been partitioned on that column.
The clause partition by reference (fk_sales_01) has the name of the foreign key in the
partition definition. This instructs Oracle Database 11g to confirm the partitioning is
done per the scheme used in the parent table—in this case, customers. Note the NOT
NULL constraint for column cust_id.; this is required for reference partitioning.

TCS Public
Interval Partitioning
• Range partitioning allows you to create partitions based on ranges of the
values of the partition key column. Here is an example of the range
partitioned table:
create table sales6
(
sales_id number,
sales_dt date
) partition by range (sales_dt)
(
partition p0701 values less than (to_date(‘2007-02-01’,’yyyy-mm-dd’)),
partition p0702 values less than (to_date(‘2007-03-01’,’yyyy-mm-dd’))
);
• Here you have defined partitions for January 2007 and February 2007 only,
so what happens if a record is inserted into the table that has the sales_dt
in March 2007? The insert will fail with the following error:
ORA-14400: inserted partition key does not map to any partition
Obviously you need to add a partition for March 2007 before you can insert a
record. But this is often easier said than done. Often you can’t afford to create a lot of
partitions beforehand and too few of them may result in this error. Wouldn’t it be
better if Oracle somehow automatically sensed the need for new partitions and then
created them?
Oracle Database 11g does, with a feature called Interval Partitioning. Here, you
don’t define partitions and their boundaries but merely an interval that defines each
partition’s boundaries. Here is the same example in interval partitioning:
create table sales6
( sales_id number,
sales_dt date)
partition by range (sales_dt)
interval (numtoyminterval(1,’MONTH’))
(
partition p0701 values less than (to_date(‘2007-02-01’,’yyyy-mm-dd’))
);

TCS Public
Note the clause: interval followed by the interval. Here you have instructed Oracle to
create intervals of one month each. You have also created the initial partition named
p0701, for the January 2007 data. Now, suppose you insert a record with June 2007
data:
SQL> insert into sales6 values (1,’01-jun-07’);
1 row created.
Oracle does not return an error; rather; it successfully executes the statement. So
where does the record go to?
The partition p0701 can’t have the record and we haven’t defined a partition for June
2007. But at this time if you check the partitions of the table:

SQL> select partition_name, high_value


from user_tab_partitions where table_name = ‘SALES6’;
PARTITION_NAME HIGH_VALUE
--------------- ----------------------------------------------------------------
P0701 TO_DATE(‘ 2007-02-01 00:00:00’, ‘SYYYY-MM-DD HH24:MI:SS’, ‘NLS_C
ALENDAR=GREGORIA
SYS_P41 TO_DATE(‘ 2007-07-01 00:00:00’, ‘SYYYY-MM-DD HH24:MI:SS’, ‘NLS_C
ALENDAR=GREGORIA

TCS Public

Anda mungkin juga menyukai