Archive for the ‘Uncategorized’ Category

du -sk to identify space usage unix

Thursday, April 8th, 2010

Find out what directories are using up disk space in unix with this command:

du -sk * | sort -n

I often put it into a function so I can call it quickly:

g () {
  du -sk * | sort -n
}

df -h (df -k on old machines) shows the filesystem disk utilisation.

Materialized Views with dbms_metadata.get_ddl

Wednesday, April 7th, 2010

See the SQL create definition of a materialized view by running this SQL:

set long 200000 pages 0 lines 131 doc off
column txt format a121 word_wrapped
spool recreate_sql
select dbms_metadata.get_ddl('MATERIALIZED_VIEW','my_mv_name','my_owner') txt from dual;
spool off
set pages 9999

Look especially for the refresh option, e.g.:

REFRESH FORCE ON DEMAND NEXT null

There are three normally used refresh options:

  • Fast = use materialized view logs on source
  • Complete = ignore materialized view logs, instead truncate the materialized view and repopulate it from the base tables of source.
  • Force = exactly the same as Fast – except when there are no materialized view logs on source, in which case it does a complete refresh.

dbms_stats export import optimizer statistics

Wednesday, April 7th, 2010

Examples of syntax to export/import dbms_stats:

exec dbms_stats.create_stat_table ( ownname => user , stattab => 'temp_stats' ) ;
exec dbms_stats.export_table_stats ( ownname => user , stattab => 'temp_stats', tabname => 'mytable', statid => 'Taken_7Apr2010') ;
exec dbms_stats.import_table_stats ( ownname => user , stattab => 'temp_stats', tabname => 'adm_fact' )

Similarly for schema:

exec DBMS_STATS.EXPORT_SCHEMA_STATS ( ownname => 'myowner' , stattab => 'temp_stats', statown => user )

A bug in 10g prevents spaces being passed into the “statid” variable, hence the underscores in the above example.

Keep log files by copying into new directory unix

Wednesday, April 7th, 2010
cp -pR logs logs`date +$d%m%y%T`

Creates a timestamped copy directory named like “logs041015:44:42″.

Show date time tables were created

Tuesday, March 30th, 2010

To see when tables (or other objects) were created, first change your date format to display time:

alter session set nls_date_format='Dy DD-Mon-YYYY HH24:MI:SS';

Then in Oracle SQL Developer, right click on the table or object in question, select ‘open‘, and look at the ‘details‘ tab.

Or alternatively still in SQL, look at the created column:

select object_name, created from user_objects order by 2;

That is for objects owned by you. For objects owned by others:

select object_name, created from all_objects order by 2;

Note that the column ‘last_ddl_time’ is not as useful as it sounds, since even operations like GRANTs on the table update the ‘last_ddl_time’.

PL/SQL to count from all tables in a schema

Friday, March 12th, 2010

Replace SYSTEM with the name of the schema you are interested in:

set serverout on size 999999
declare
  cnt number ;
begin
  for c1 in (select owner, table_name from all_tables where owner = 'SYSTEM')
  loop
    execute immediate 'select count(1) from '||c1.owner||'.'||c1.table_name into cnt ;
    dbms_output.put_line(c1.table_name||','||cnt) ;
  end loop ;
end ;
/

Automatic gather stats job

Friday, March 5th, 2010

check it is on with:

select state, last_start_date from dba_scheduler_jobs where job_name = 'GATHER_STATS_JOB' ;

Switch it on and off with:

exec dbms_scheduler.disable('GATHER_STATS_JOB')
exec dbms_scheduler.enable('GATHER_STATS_JOB')

/etc/cron.d not working fails

Thursday, February 25th, 2010

Files in /etc/cron.d only work if they are not executable files (at least that is the case on newer version of unix/linux).

Oracle Performance Tuning Notes

Friday, April 17th, 2009

Click for the Course notes with scripts for a 3 day performance tuning course I did recently.

schema moves by the magic of partition exchange

Friday, April 17th, 2009

Here’s an example of how to use partition exchange to move partitions or even entire unpartitioned tables from one schema to another. Is mean to be very fast and generate very little redo. Even more so if the partitions and tables are kept in the same tablespace.

Process for doing partition exchange is like this:

– first create the archive table, empty initially:

create table arch_owner.mytable .... [full create table spec goes in here, including partition clauses, but leave out the primary key/index ]

– give arch_owner (or alternatively whichever user runs this job) the required privileges

grant select, alter on live_owner.mytable to arch_owner ;

– create an empty temporary table, used later in the partition exchange

create table arch_owner.temp_table as select * from live_owner.mytable where 1=2 ;

– exchange the live partition with the temporary table

alter table live_owner.mytable exchange partition year2001 with table arch_owner.temp_table ;

– exchange that onwards to the archived table

alter table arch_owner.mytable exchange partition year2001 with table arch_owner.temp_table ;

– at the very end of the process, clean up the temporary table, add in any required primary keys or other indexes, and gather optimizer stats (=analyze)

drop table arch_owner.temp_table ;
alter table arch_owner.mytable add primary key (aud_id) using index tablespace ts_index1 ;
exec dbms_stats.gather_schema_stats('ARCH_OWNER', estimate_percent=>99.99, cascade => TRUE, method_opt=> 'FOR ALL INDEXED COLUMNS SIZE 1')

> On a similar vein, is there an elegant way of copying the current data from the live_owner.mytable table to the arch_owner.mytable table? About 15Gb of data would normally go across via our scripts, but unfortunately the tables aren’t partitioned to let us do something along the lines of your last suggestion …

1) Yes, can do it in essentially the same way as before (h/t Pythian Blog):

– give arch_owner the required privileges on the live table:

grant select, alter on live_owner.mytable to arch_owner ;

– create an empty table and index in arch_owner

create table df_arch_owner.mytable .. [full create table spec here]
create index arch_owner.mytable_index1 on arch_owner.mytable (to_date(plan_date,'YYYY-MM-DD') ) tablespace ts_index1 ;

– also create a temporary table with a single dummy partition

create table arch_owner.temp_table
partition by range ( userid )
( partition dummy values less than ( maxvalue ) )
as select * from arch_owner.mytable where 1=2 ;

– again with an index (locally):

create index arch_owner.temp_index1 on arch_owner.temp_table (to_date(plan_date,'YYYY-MM-DD') ) tablespace ts_index1 local ;

– swap the live table and the temporary table with each other:

alter table arch_owner.temp_table exchange partition dummy with table live_owner.mytable
including indexes without validation ;

– then swap the temporary table and the arch_owner table with each other:

alter table arch_owner.temp_table exchange partition dummy with table arch_owner.mytable
including indexes without validation ;

– optimizer stats for both schemas should be re-gathered at the overall completion of the archiving work, and temporary tables dropped.

2) Or alternative method – but probably not so good because it doesn’t strictly move from one schema to the other, just renames:

– login as live_owner

conn live_owner/password

– rename the old table to have arch_ in front of its name

rename mytable to arch_mytable ;

– rename the old index to have arch_ in front of its name

alter index mytable_index1 rename to arch_mytable_index1 ;

– create a synonym in arch_owner that points to the arch_ table.

create synonym arch_owner.arch_mytable for live_owner.arch_mytable ;

– and also grant arch_owner privileges on the arch_ table

grant select on live_owner.arch_mytable to arch_owner ;

– create a new empty table in live_owner, complete with indexes, triggers, grants, and so on:

create table live_owner.mytable ....
create index mytable_index1 on live_owner.mytable ....
create trigger live_owner.del_mytable ....
grant select, insert, ....

– optionally can move the arch tables from one tablespace to the other (although I don’t see how that could be worth the substantial time and effort that it takes):

alter table arch_mytable move tablespace ts_arch_data ;
alter index arch_mytable_index1 rebuild tablespace ts_arch_index ;

– optimizer stats for both schemas should be re-gathered at the overall completion of the archiving work.

Changing Tablespaces in Partition Exchange

If you need objects to be in specific tablespaces, you should explicitly state that tablespace name, otherwise you can expect the users default tablespace will be used instead. That applies to all operations that alter indexes and tables – including exchange partition, enable constraint, create constraint, create index, alter index rebuild, create table, alter table add partition, and so on.

For partition exchanges, it is a bit more complex than that, because exchanged partitions take their tablespace with them during the exchange.

So imagine an initial setup where the live year2001 partition is in ts_data1, and the other two objects to be used are in tablespaces “X” and “Z”:

Object Tablespace
live_year2001 ts_data1
temp table X
archive_year2001 Z

After we exchange “live year 2001″ with “temp table” their tablespaces swap:

Object Tablespace
live_year2001 X
temp table ts_data1
archive_year2001 Z

Then exchange “archive year 2001″ with “temp table”, same thing happens:

Object Tablespace
live_year2001 X
temp table Z
archive_year2001 ts_data1

Then we drop the “temp table”:

Object Tablespace
live_year2001 X
archive_year2001 ts_data1

Now, assuming we want tablespace “X” to be ts_data1, checking back to the initial setup shows that that tablespace was the one defined by the temp table. So it is important to explicitly specify that tablespace, using code like:

– create an empty temporary table, used later in the partition exchange

create table arch_owner.temp_table tablespace ts_data1
as select * from live_owner.mytable where 1=2 ;

Also, assuming we want the “archive year2001” partition to be in ts_arch_data, we have a problem – it has ended up in ts_data1. There is no way to prevent that at the time, instead it has to be moved at the end, using:

alter table arch_owner.owner.mytable move tablespace ts_arch_data ;

That table move is unfortunately slow and generates redo.