create table orders (
order_id number not null,
order_date date not null,
customer_id number not null
) tablespace tbs1
partition by range (order_date) (
partition orders_y2011 values less than (to_date('01-JAN-2012', 'dd-mon-yyyy')) tablespace tbs1,
partition orders_y2012 values less than (to_date('01-JAN-2013', 'dd-mon-yyyy')) tablespace tbs1,
partition orders_y2013 values less than (to_date('01-JAN-2014', 'dd-mon-yyyy')) tablespace tbs1
);
alter table orders add constraint orders_pk primary key(order_id) using index tablespace tbs1;
create index orders_ix1 on orders(customer_id)
tablespace tbs1
local
(
partition orders_ix1_y2011 tablespace tbs1,
partition orders_ix1_y2012 tablespace tbs1,
partition orders_ix1_y2013 tablespace tbs1
);
-- 1. Referential constraint must be defined while creating table.
-- 2. PARTITION BY REFERENCE clause should be used for reference partitioning
-- and it should mention referential constraint name.
create table order_items (
order_id number not null,
product_id number not null,
price number,
quantity number,
constraint order_items_fk foreign key (order_id) references orders
) tablespace tbs1
partition by reference (order_items_fk) (
partition order_items_y2011 tablespace tbs1,
partition order_items_y2012 tablespace tbs1,
partition order_items_y2013 tablespace tbs1
);
alter table order_items add constraint order_items_pk primary key(order_id, product_id) using index tablespace tbs1;
create index order_items_ix1 on order_items(order_id)
tablespace tbs1
local
(
partition order_items_ix1_y2011 tablespace tbs1,
partition order_items_ix1_y2012 tablespace tbs1,
partition order_items_ix1_y2013 tablespace tbs1
);
-- While adding partition to parent table, we can use
-- 1. DEPENDENT TABLES clause to specify names of child partitions
-- 2. In UPDATE INDEXES clause, we can give indexes of parent and child tables.
alter table orders
add partition orders_y2014
values less than (to_date('01-JAN-2015', 'dd-mon-yyyy'))
tablespace tbs1
dependent tables (
order_items (partition order_items_y2014 tablespace tbs1)
)
update indexes (
orders_ix1 (partition orders_ix1_y2014 tablespace tbs1),
order_items_ix1 (partition order_items_ix1_y2014 tablespace tbs1)
)
;
-- Dropping parent partition will drop child table partition(s), and corresponding index partitions
alter table orders drop partition orders_y2011 update global indexes;
Few details about my experiments and experiences with technologies of Oracle database and Linux
Friday, November 29, 2013
Reference partitioning example
Decrypting Oracle database DB link password (Versions <= 11.2.0.2)
-- Run as SYS user
set serveroutput on
declare
db_link_password varchar2(100);
begin
db_link_password := '0560A31A6EFEC902B9286FFC981F4C9A92F8470D406ADEA670';
dbms_output.put_line ('Plain password: ' ||
-- Convert RAW to varchar2
utl_raw.cast_to_varchar2 (
dbms_crypto.decrypt (
-- from 19th char to end, it is encrypted source
substr (db_link_password, 19) ,
-- Type of encryption
dbms_crypto.DES_CBC_PKCS5 ,
-- From 3rd to 16th char, it is key
substr (db_link_password, 3, 16)
)
)
);
end;
/
Plain password: Forget12
Dropping Database link in another schema
Oracle
database does not allow to drop database link owned by another user.
As a DBA user, to drop database link in another schema, here are
steps to follow.
1. Create a procedure in another schema in which database link exists
2. The procedure should have statement to drop database link
3. Execute the procedure
4. Drop the procedure
These steps can be written as PL/SQL anonymous block like below.
declare
schema_name
varchar2(10)
:=
'MURTY';
--
db_link_name should be same as value of DB_LINK column in
DBA_DB_LINKS view
db_link_name
varchar2(100)
:=
'remote.xyz.com';
random_proc_name
varchar2(100);
cnt
number;
begin
schema_name
:=
upper(schema_name);
db_link_name
:=
upper(db_link_name);
--
A random procedure to make sure the name of procedure should not
conflict with existing procedures
random_proc_name
:=
schema_name ||
'.drdl_'
||
dbms_random.string('U',
20);
select
count(*)
into
cnt from
dba_db_links where
owner=schema_name
and
db_link=db_link_name;
if
(
cnt !=
1
)
then
raise_application_error(-20001,
'DB
Link does not exist');
end
if;
--
1. Create a procedure in another schema in which database link exists
execute
immediate
'
create procedure '
||
random_proc_name ||
'
as '
||
'
begin '
||
--
2. The procedure should have statement to drop database link
'
execute immediate ''drop database link '
||
db_link_name ||'
''; '
||
'
end;';
begin
--
3. Execute the procedure
execute
immediate
'begin
'
||
random_proc_name ||
';
end;';
exception
when
others
then
execute
immediate
'drop
procedure '
||
random_proc_name;
raise;
end;
--
4. Drop the procedure
execute
immediate
'drop
procedure '
||
random_proc_name;
end;
/
Wednesday, February 27, 2013
Generating DDL of a schema using datapump
Here is the method to get entire DDL of a schema in SQL using
datapump. In this example, we are trying to get DDL of a schema called
MYSCHEMA.
Export entire schema metadata into a dump file. It will be created in
directory MYDIR. To this work, first there should be a directory object MYDIR
in database.
expdp murty@mydb schemas=MYSCHEMA directory=MYDIR
dumpfile=schema_metadata.dmp content=METADATA_ONLY
Now we can extract SQL from the dump file like below.
impdp murty@mydb directory=MYDIR dumpfile=schema_metadata.dmp
sqlfile=schema_metadata.sql exclude=STATISTICS
Estimate savings of disk space by shrinking a table
This post shows how to estimate disk space savings of
shrinking a table. Here we are using Segment space advisor task.
-- Create a table
and make it fragmented
SQL> create
table tab1 (a number, b varchar2(10));
Table created.
-- Filling table
with 1 million records
begin
for i in 1
.. 1000000
loop
insert into tab1 values(i, 'AAAAAAAAAA');
end loop;
commit;
end;
/
SQL> select
count(*) from tab1;
COUNT(*)
----------
1000000
-- Check the space
usage in MB
SQL> select
bytes/(1024*1024) from user_segments where segment_name='TAB1';
BYTES/(1024*1024)
-----------------
23
-- Let
us fragment it by deleting 90% of records evenly across table
SQL> delete from
tab1 where mod(a, 10) != 1;
900000 rows
deleted.
SQL> commit;
Commit complete.
SQL> select
count(*) from tab1;
COUNT(*)
----------
100000
-- We see that it
still using same space
SQL> select
bytes/(1024*1024) from user_segments where segment_name='TAB1';
BYTES/(1024*1024)
-----------------
23
Here is the script to estimate space savings if we do
shrink space.
declare
tname
varchar2(100);
oid number;
tid number;
begin
tname:='CHECK_SHRINKABLE_1';
dbms_advisor.create_task
(
advisor_name
=> 'Segment Advisor',
task_id
=> tid,
task_name
=> tname);
dbms_advisor.create_object
(
task_name
=> tname,
object_type
=> 'TABLE',
attr1
=> 'MURTY',
attr2
=> 'TAB1',
attr3
=> NULL,
attr4
=> NULL,
attr5
=> NULL,
object_id
=> oid);
dbms_advisor.set_task_parameter(
task_name
=> tname,
parameter
=> 'recommend_all',
value
=> 'TRUE');
dbms_advisor.execute_task(tname);
end;
/
We can use the view USER_ADVISOR_RECOMMENDATIONS view to
check result.
SQL> set
linesize 110
SQL> select
BENEFIT_TYPE from USER_ADVISOR_RECOMMENDATIONS where
TASK_NAME='CHECK_SHRINKABLE_1';
BENEFIT_TYPE
--------------------------------------------------------------------------------------------------------------------------------------------
Enable row movement
of the table MURTY.TAB1 and perform shrink, estimated savings is 17512778
bytes.
Let us shrink the table and check the space usage.
SQL> alter table
tab1 enable row movement;
Table altered.
SQL> alter table
tab1 shrink space;
Table altered.
SQL> select
bytes/(1024*1024) from user_segments where segment_name='TAB1';
BYTES/(1024*1024)
-----------------
2.4375
Subscribe to:
Posts (Atom)