Monday, January 22, 2007

Conversion of '07 - Still Processing

Well the ftp and load process is still going at 130 hours, but so far very few errors, and the few that are happening are easily by passable or fixable. I am very pleasantly surprised. Our estimates have greatly increased due to the higher than expected bandwidth use by the users during business hours. If everything continues on track the last file should be sent via FTP on this coming Wednesday morning.

I used a combination of DBMS_META_DATA and CTAS , extracted the create DDL and created the entire database sans data on my laptop and have gotten all of the DDL for the PL/SQL ran and the majority of the objects created. A boatload of errors and uncompiled PL/SQL, but at least it is all there.The project from the oracle end is ticking along nicely.

From the hardware end, well that is another story. The hardware to replace the VMS system oh man, people that say "disk is cheap" need to have their heads examined! To increase the capacity on our SAN to hold this new DB, this includes the drives themselves, a new drive enclosure, cabling, more room on the DAS (more drives) on the tape array to hold near line backup, another 25 tapes for the tape array for the offline/offsite and various odds and ends to make all that happen - initial estimate, $425,000. We almost fell off of our chairs at that. That was just the storage for the DB. The application server estimate from HP via our broker is in, $375,000 and we can't have it for 45 days.


Sunday, January 21, 2007

The conversion of '07

5 days straight on this project, averaging 15 hours a day for 6 "in house" IT staff and 5 consultants. Took today off as it is Sunday, but I had to come into the office to do the "real" work that has been missed. This coming week is not going to show much work internally on this as other projects are taking priority. I used sqlplus and extracted all of the DDL for the programs and triggers, 109.302 megabytes of text DDL files (uncompressed). That was a shocker, even with almost 6,000 PL/SQL that is a huge amount.

I was made the official "Project Lead", that means that today, after spending 6-8 hours to find out why backups were failing last week and delegate the user requests that flowed in, I get to transpose the project task list and milestones into a Gant chart for our status meeting on Friday. I have to devise a project time line that will have this system running on a Linux back-ended database and the front end running on an ancient HP-UX server that was slated for the trash bin no later than the middle of April 2007. One of our SA's called HP to see about getting some warranty and parts coverage on the ancient server and the possibility of adding a CPU. He was literally laughed at, HP is looking into it and will get back to him with some options, we hope they have some newer hardware that can run the older OS and we will simply purchase the hardware. On the purchase note, we were given an almost blank check for this project on Friday, simply "keep it under 6 million", that dollar figure does not count internal IT time ("free") or the consultants who's time gets divided up and charged to the sites. The sites had came back some what appears to be valid numbers that for every day they do not have this system the chance of a processing line failure increases by 1.2%, even the smallest plant going down will cost the company $125,000 a day with the largest plant showing a net loss of $1.1 million a day. There are 17 sites that will be exposed, that woke the management up. The customer interaction and shipping data retrieved from the system is another story and can not be quantified easily into a dollar figure, the note was something to the effect of

How much is it worth when a customer who buys a million a month worth of product asks "When will my order by completed?" and the companies answer is "We don't know, our system is down".


I called our Oracle sales rep on Thursday, to talk about the licensing implications of this move, I loved the answer I got back on Friday morning - "Won't cost you any more oracle licensing as long as the old system is turned off within 60 days of the new system coming online, your covered - need any consulting?".


As I sat here writing this, 4 other IT staff showed up without being asked to catch up on missed work and work on this project. I like the people I work with.

Thursday, January 18, 2007

Some good progress

Well, we made some really good progress today with the DW conversion. We carved off 400 gig section of our SAN even before the new disks have arrived, and created a 10gR2 DB there in noarchive mode. I built a DCL script that runs on the VMS cluster and exports one table at a time from a list that we compiled to a distinct file name, then FTP's the export file to the Linux server with the new LUN mounted. Then the Linux server imports those tables into the new DB and sends a notification if there are any failures. We have created all of the tables already in the DB and spread out the tables over multiple tablespaces. This is more for our ease of management than anything performance based. The process has been running for about 7 hours now and has sent 1,079 tables with very few failures, but the big tables are still to come, with the throughput we are getting, are estimates are about 120-130 hours. The import process imports 4 files at a time as any more than that saturates the IO on the linux box. This is of course simply a test to see what will fail and give us an idea on how long we will have to book downtime for. The largest slow down is the network link between the 2 sites, we 100% utilize the network link. The network folks are going to investigate some point to point VPN's as they are confident they can get 3 or 4 dedicated ADSL lines into the remote site and our internet pipe is much larger (x10) than the dedicated network link.

I think our downtime will be limited though, The data import process can be stopped and only a select few users have rights assigned by the application to make data changes. We will remove those rights via the application, then stop the data load process and start the transfer when we do this for real. That will mean the users will be able to query the old system while the data is being transfered. The consultants have been very successful in "fooling" the application to connect to the test database on the linux server, took some work on their side though. They knew they were able to compile the application on an older HP-UX PA-RISC series running V10 of the OS, luckily we had one. On that server we were able to install an oracle 9 client which their application recognizes and will still connect to the 10g database. They have about 3 weeks of work to finish the application move to the HP-UX server though and that does not include any testing or recoding the inevitable failures. We have a consulting company coming up next week to work on converting the VMS DCL script portion of the system to unix shell scripts. That is going to be interesting working through that conversion.

Tomorrow we tackle the triggers and PL/SQL code and see what fails there. 15 hours at the office today is enough for me.



Tuesday, January 16, 2007

OCP certification and knowledge

I have mentioned before that Howard Rogers is a great man, and this post proves it. Absolutely no argument from me on this.

I too have written in many places about the "dead from the neck up" job candidates I have been through over the years, OCP certification is a joke and a waste of money for companies. The people who have proclaimed themselves experts "OCP Certified" who can't answer the simplest of database questions.

I will put the list of questions we ask up on a post very soon.




New project, time for a new job?

A few years ago the company I work for purchased another company of almost the same size effectively doubling our size.

During this acquisition, we in the IT group were told about some of the systems that were in place, but luckily other than the core applications we didn't have to do anything about the older systems at all. There were consultants who managed the systems and the servers were housed far from the IT group. An "Out of Site, Out of Mind" deal.

Well, yesterday, that changed for one particular system. Our manager got a call that the 3 person consulting company that looks after the "data warehouse database" for 17 of our sites has put decided to not renew the contract which expires in 90 days, effectively dropping the management of the database into the IT group's laps. This has happened before, we took it in stride. Until the DBA's got access to take a look at the DB yesterday afternoon. Oh boy... I checked to make sure the headhunter firm I use had an up to date CV and I removed my restriction on not wanting to work in the United States.

Oracle database version 7, with an astounding 3,319 tables in a single schema with only one primary key constraint created on one table. No database referential integrity at all. 891 procedures, 4319 triggers, 771 functions (no packages). OS is OpenVMS running on some really old Digital Equipment hardware. The front end uses proprietary VMS DCL scripting coupled with a Fortran VT100 terminal user interface. Total database storage across the 8 Vax/VMS machines in the cluster - 636 gigabytes with 432 gigabytes of that being the database (according to dba_segments). Apparently backups are cold backup's that start on Friday night at 10pm and finish early Monday morning if there were no problems, it is noted that sometimes the database can go 4-6 weeks without a backup during the heavy work season because the data is needed 24 hours a day 7 days a week and the database can not be shut down. At least it is running in archive log mode. Sites send data to the database via file transfer every morning and the data is loaded some what manually by some clerks at one site.

Management asked us how long it would take to convert the data to an oracle 10g database (or 11g) on linux so a development team can be put together to build a new front end because apparently they sites can not live without that data that goes into that database, once the data is converted to 10g on Linux then we can look at redesigning the entire system but downtime has to be minimal. I was handed the "documentation" that the consulting firm has done to date, and was promised the bulk of the remaining time the consultants have on contract will be dedicated to writing better documentation. I would hope so, because the documentation I tried to read last night looks like it was written by a 11 year old in a hurry to complete a school work assignment. We also got a 3 inch binder stuffed full of about the last years worth of user requests, user filed problems and "bug" tracking that the consultants have - nothing electronic at all, all done by hand. I have until this coming Monday to come up with a realistic plan on converting the data to oracle 10g.

This project scares me, this is far past the "take it as a challenge" or "show off your skills" that the management is throwing around, I see this becoming a career ruining and stress related heart attack inducing project. Anybody out there looking for an experienced level headed Oracle DBA with years of experience in both DBA skills and development skills? :)


I think this project will be the seed of hundreds of blog posts.






Friday, January 05, 2007

Blogger and formatting

I forgot just how hard it is to get something to format the way I want it on blogger, I think I will have to do some research on another blogspace.


Old Questions refreshed again

Saw somebody bumped one of the many "is select count(1) faster than select count(*)" threads on AskTom .

I believe Tom, but I just had to go and look AGAIN to see if anything changed in 10gR2:

SQL> select count(1) from dbtesting.t; 

COUNT(1) 
---------- 
20413 

Elapsed: 00:00:00.00 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2966233522 

------------------------------------------------------------------- 
| Id | Operation | Name | Rows | Cost (%CPU)| Time | 
------------------------------------------------------------------- 
| 0 | SELECT STATEMENT | | 1 | 59 (2)| 00:00:01 | 
| 1 | SORT AGGREGATE | | 1 | | | 
| 2 | TABLE ACCESS FULL| T | 20413 | 59 (2)| 00:00:01 | 
------------------------------------------------------------------- 


Statistics 
---------------------------------------------------------- 
0 recursive calls 
0 db block gets 
315 consistent gets 
0 physical reads 
0 redo size 
413 bytes sent via SQL*Net to client 
381 bytes received via SQL*Net from client 
2 SQL*Net roundtrips to/from client 
0 sorts (memory) 
0 sorts (disk) 
1 rows processed 

SQL> select count(*) from dbtesting.t; 

COUNT(*) 
---------- 
20413 

Elapsed: 00:00:00.00 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2966233522 

------------------------------------------------------------------- 
| Id | Operation | Name | Rows | Cost (%CPU)| Time | 
------------------------------------------------------------------- 
| 0 | SELECT STATEMENT | | 1 | 59 (2)| 00:00:01 | 
| 1 | SORT AGGREGATE | | 1 | | | 
| 2 | TABLE ACCESS FULL| T | 20413 | 59 (2)| 00:00:01 | 
------------------------------------------------------------------- 


Statistics 
---------------------------------------------------------- 
0 recursive calls 
0 db block gets 
315 consistent gets 
0 physical reads 
0 redo size 
413 bytes sent via SQL*Net to client 
381 bytes received via SQL*Net from client 
2 SQL*Net roundtrips to/from client 
0 sorts (memory) 
0 sorts (disk) 
1 rows processed 

SQL> select count(66666) from dbtesting.t; 

COUNT(66666) 
------------ 
20413 

Elapsed: 00:00:00.00 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2966233522 

------------------------------------------------------------------- 
| Id | Operation | Name | Rows | Cost (%CPU)| Time | 
------------------------------------------------------------------- 
| 0 | SELECT STATEMENT | | 1 | 59 (2)| 00:00:01 | 
| 1 | SORT AGGREGATE | | 1 | | | 
| 2 | TABLE ACCESS FULL| T | 20413 | 59 (2)| 00:00:01 | 
------------------------------------------------------------------- 


Statistics 
---------------------------------------------------------- 
1 recursive calls 
0 db block gets 
315 consistent gets 
0 physical reads 
0 redo size 
417 bytes sent via SQL*Net to client 
381 bytes received via SQL*Net from client 
2 SQL*Net roundtrips to/from client 
0 sorts (memory) 
0 sorts (disk) 
1 rows processed 

SQL> select count(dbms_random.value(1,1000)) from dbtesting.t; 

COUNT(DBMS_RANDOM.VALUE(1,1000)) 
-------------------------------- 
20413 

Elapsed: 00:00:00.17 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2966233522 

------------------------------------------------------------------- 
| Id | Operation | Name | Rows | Cost (%CPU)| Time | 
------------------------------------------------------------------- 
| 0 | SELECT STATEMENT | | 1 | 59 (2)| 00:00:01 | 
| 1 | SORT AGGREGATE | | 1 | | | 
| 2 | TABLE ACCESS FULL| T | 20413 | 59 (2)| 00:00:01 | 
------------------------------------------------------------------- 


Statistics 
---------------------------------------------------------- 
1 recursive calls 
0 db block gets 
315 consistent gets 
0 physical reads 
0 redo size 
437 bytes sent via SQL*Net to client 
381 bytes received via SQL*Net from client 
2 SQL*Net roundtrips to/from client 
0 sorts (memory) 
0 sorts (disk) 
1 rows processed 

SQL> spool off 



> >


There, now if somebody somebody is wondering, the argument is solved. They are the same when selecting from a table without a predicate, I even threw in the dbms_random to show any number in the count() is the same.



Tuesday, January 02, 2007

Dizwell is Back

Ahhh... there we go.


Howard relented and opened his site again. Howard is a great guy!

http://www.dizwell.com



Saturday, December 30, 2006

ORA-07445

It is interesting to actually listen to users occasionally, down right extraordinary. Take this for example.

I was surprised to see on a brand new oracle 10gR2 DB which sole purpose s to test the application for upgrading from 9iR2 this error come through our monitoring script:

ORA-07445: exception encountered: core dump [kddlkr()+748] [SIGBUS] [unknown code] [0x000000010] [] []

Within 1 minute the 9i database on the same server,

ORA-07445: exception encountered: core dump [kddlkr()+748] [SIGBUS] [unknown code] [0x000000010] [] []

Remarkable, two different homes, two different databases, two different application installs with the same error.

Search on metalink comes back with the dreaded:

A Description for this ORA-7445 error is not available.
Your request has been recorded and will be used for publishing prioritization.
Doing an Advanced Search on ORA-7445 'kddlkr' which may help to provide additional information on this error...

After about an hour of fruitless searching on metalink and trace file diving, I decided to call around to the users and see if anybody had received an error message. I found a very nice lady who had recently received an error in the application, she explained to me in great detail on exactly what she was doing to test the new version of the application. I was taken aback by her attention to detail and since she was just 2 floors up, I decided to visit her. She had almost 30 pages of checklists and notes that she had written over the years and the many different versions of this application of things she has to test every time a new version is released. She explained that this one module consistently gives an error when the user first opens the screen, and has done so for 3 years and 4 versions of the application, she had diligently written down the exact application error code in her notes for each of her testing sessions on the new applications all with the exact date and time noted.

I was properly impressed and told her so, I had her go into the module and show me the error, and sure enough, the error box pops up and exactly matches her hand written notes, it felt like the world had stopped spinning and I was wondering why I had never heard from this magnificent lady before, surely she was next in line for the "Power User" member of the application team. I asked her if the vendor or our local application support people had given her a work around or a valid excuse to this error. Her answer set the world spinning again after it's brief stoppage - her words "I have never told anybody about it, because it has always had an error since I started, I just tested to see if it had started to work with the new version, we don't even know what the module does."

So close, but yet so far. I will task the local application support people to investigate this error and open a ticket with the vendor.



Friday, December 29, 2006

Dizwell is gone

I take a few months of reading off and Howard Rogers leaves in that time, talk about horrible timing on my part.


There is some discussion of the closing of the site here


http://oraclesponge.wordpress.com/2006/12/27/so-farewell-then-dizwell/


I wish Howard well, and hope to bump into him on-line.

Cheers Howard!


What happened to Dizwell?

I grabbed a cup of tea, settled in for a good long read of Dizwell to catch up on what I missed... and its gone.


http://www.dizwell.com/


Comes back to


Welcome to dizwell.com !

This is a place-holder for the dizwell.com home page.



He can't be gone? can he?

Back (again)

Well, after a lengthy period of time, I am back, and planning on blogging again. Normal things got in the way - like work, divestitures, purchases and mergers, and family life which caused blogging to be dropped right off of the to-do list.

I haven't even been reading or participating in any forums or other blogs until yesterday. So I am back and ready to roll.

So if there is still anybody out there reading this, thanks for sticking around and I promise some stuff soon.


Wednesday, November 01, 2006

Primary And Unique Keys


Unique and Primary Constraints

There was some confusion on if a primary key constraint allowed multiple null values, or if a

unique constraint actually enforced the uniqueness of null values. So, here is the answer to those

questions.

Primary Keys

Let us start with primary key constraints. I will build a few objects to help us out.

SQL> CREATE SEQUENCE SOMETEST;

Sequence created.

SQL>

SQL> CREATE TABLE TEST1

2 (DATACOLUMN NUMBER NOT NULL);

Table created.

SQL> CREATE TABLE TEST2

2 (DATACOLUMN NUMBER PRIMARY KEY);

Table created.

SQL> CREATE TABLE TEST3

2 (DATACOLUMN NUMBER PRIMARY KEY NOT NULL);

Table created.

SQL> CREATE TABLE TEST4

2 (DATACOLUMN NUMBER);

Table created.

To standardize the testing data, here I will create a table and populate it so that we can use as a base

for the upcoming inserts. I will put in 5 rows of data at creation and two rows of null.

SQL> CREATE TABLE SOMEDATA AS SELECT SOMETEST.NEXTVAL DATACOLUMN FROM DUAL CONNECT BY

LEVEL <= 5;

Table created.

SQL> INSERT INTO SOMEDATA (DATACOLUMN) VALUES (NULL);

1 row created.

SQL> INSERT INTO SOMEDATA (DATACOLUMN) VALUES (NULL);

1 row created.

SQL> COMMIT;

Commit complete.

SQL> SELECT DATACOLUMN,DECODE(DATACOLUMN,NULL,'Y','N') ISNULL FROM SOMEDATA;


DATACOLUMN ISNULL

---------- ----------

1 N

2 N

3 N

4 N

5 N

Y

Y

7 rows selected.

You can see there are 7 rows of data, all unique except for two rows of null values.

First we will do a simple insert into from a full query of the SOMEDATA table.

SQL> INSERT INTO TEST1 SELECT DATACOLUMN FROM SOMEDATA;

INSERT INTO TEST1 SELECT DATACOLUMN FROM SOMEDATA

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST1"."DATACOLUMN")

The above results were pretty much expected, the column is marked as NOT NULL meaning of

course, no null values at all are allowed.

Now to try the same insert into the TEST2 table with the primary key.

SQL> INSERT INTO TEST2 SELECT DATACOLUMN FROM SOMEDATA;

INSERT INTO TEST2 SELECT DATACOLUMN FROM SOMEDATA

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST2"."DATACOLUMN")

So, a primary key is automatically NOT NULL. So when we created the table TEST3 we simply did

not need to add the NOT NULL parameter to the column. For completeness here is the same insert

carried out on the TEST3 table.

SQL> INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA;

INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST3"."DATACOLUMN")

No surprises there. The insert failed.

Now for TABLE4 the table was created with no constraints at all. So now if we do the insert, all 7

of the rows will go into the table.

SQL> INSERT INTO TEST4 SELECT DATACOLUMN FROM SOMEDATA;

7 rows created.

SQL> COMMIT;

Commit complete.


If we are now to add a primary key constraint to the table

SQL>

SQL> ALTER TABLE TEST4 ADD CONSTRAINT TEST4PK

2 PRIMARY KEY (

3 DATACOLUMN

4 )

5 /

ERROR at line 3:

ORA-01449: column contains NULL values; cannot alter to NOT NULL

The database automatically tries to put a NOT NULL check constraint on the column, adding the

primary key fails.

If we try to add the primary key with the command option of NOVALIDATE, the table is altered

and the primary key is added.

1 ALTER TABLE TEST4 ADD CONSTRAINT TEST4PK

2 PRIMARY KEY (

3 DATACOLUMN

4* ) NOVALIDATE

SQL> /

Table altered.

After the primary key is on with the NOVALIDATE we still are unable to insert a null value into

TEST4.

SQL> INSERT INTO TEST4 (DATACOLUMN) VALUES (NULL);

INSERT INTO TEST4 (DATACOLUMN) VALUES (NULL)

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST4"."DATACOLUMN")

Even though TEST4 contains null values

1* SELECT DATACOLUMN,DECODE(DATACOLUMN,NULL,'Y','N') ISNULL FROM TEST4

SQL> /

DATACOLUMN I

---------- -

1 N

2 N

3 N

4 N

5 N

Y

Y

7 rows selected.

That situation is one you should be aware of. Even though the primary key is in place, there is bad

data in the table that could throw a large wrench into a well running application.


Unique Keys

Now for unique keys, we will create the same base data table as for primary keys and create new

tables with testing unique keys.

SQL> CREATE TABLE TEST1

2 (DATACOLUMN NUMBER);

Table created.

SQL> CREATE TABLE TEST2

2 (DATACOLUMN NUMBER UNIQUE);

Table created.

SQL> CREATE TABLE TEST3

2 (DATACOLUMN NUMBER UNIQUE NOT NULL);

Table created.

Now for the inserts, first start with TEST1, no constraints at all

SQL> INSERT INTO TEST1 SELECT DATACOLUMN FROM SOMEDATA;

7 rows created.

The TEST2 table has a unique constraint so most people will expect the insert to fail.

SQL> INSERT INTO TEST2 SELECT DATACOLUMN FROM SOMEDATA;

7 rows created.

But no, all 7 rows go in. Unique constraints do not count nulls when checking for uniqueness.

Now, TABLE3 has an unique key and has been set as NOT NULL

SQL> INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA;

INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST3"."DATACOLUMN")

SQL> COMMIT;

Commit complete.

A quick couple of queries to verify the data

SQL> SELECT DATACOLUMN,DECODE(DATACOLUMN,NULL,'Y','N') ISNULL FROM TEST1;

DATACOLUMN ISNULL

---------- ----------

1 N

2 N

3 N

4 N

5 N

Y

Y

7 rows selected.

SQL> SELECT DATACOLUMN,DECODE(DATACOLUMN,NULL,'Y','N') ISNULL FROM TEST2;

DATACOLUMN ISNULL

---------- ----------

1 N

2 N

3 N

4 N

5 N

Y

Y

7 rows selected.

SQL> SELECT DATACOLUMN,DECODE(DATACOLUMN,NULL,'Y','N') ISNULL FROM TEST3;

no rows selected

Constraint Objects

The objects that are created when a constraint is created are worthwhile mentioning as well. You

know what this means, time for more test objects, I can feel your joy at this prospect from here.

SQL> CREATE TABLE TEST1

2 (DATACOLUMN NUMBER PRIMARY KEY);

Table created.

SQL> desc test1

Name Null? Type

------------------------------------------------------- -------- ---------------

DATACOLUMN NOT NULL NUMBER

Simple table you have seen before with the primary key defined at creation. The system will

automatically make up a name for the constraint and apply it to the table. If you try this on your

own, your constraint and index name will be different. You can create the constraints with

whatever name you choose, check the documentation on how to do that.

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST1';

CONSTRAINT_NAME C INDEX_NAME

------------------------------ - ------------------------------

SYS_C006436 P SYS_C006436

You can see, to efficiently check for violations of the constraint, the database also automatically

creates an index on the table. The INDEX_NAME column clearly shows this. A quick query into

the USER_INDEXES view will confirm this.

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST1';

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

SYS_C006436 NORMAL UNIQUE

You will notice that the DATACOLUMN is marked as NOT NULL and there is a constraint on the

table saying so. Observe

SQL> CREATE TABLE TEST2

2 (DATACOLUMN NUMBER PRIMARY KEY NOT NULL);

Table created.

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST2';

CONSTRAINT_NAME C INDEX_NAME

------------------------------ - ------------------------------

SYS_C006437 C

SYS_C006438 P SYS_C006438

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST2';

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

SYS_C006438 NORMAL UNIQUE

SQL> desc test2

Name Null? Type

------------------------------------------------------- -------- ---------------

DATACOLUMN NOT NULL NUMBER

The database created a CHECK constraint called SYS_C006437 in this case on the table. One

reason this is done is to allow you to drop the primary key constraint and still keep the NOT NULL

constraint. A quick run of the DBMS_METADATA.GET_DDL function will show us what the

database did.

SQL> SELECT DBMS_METADATA.get_ddl('CONSTRAINT','SYS_C006437') FROM DUAL;

DBMS_METADATA.GET_DDL('CONSTRAINT','SYS_C006437')

--------------------------------------------------------------------------------

ALTER TABLE "DBTESTING"."TEST2" MODIFY ("DATACOLUMN" NOT NULL ENABLE)

Something to note is if there is already an index on the column and you add a constraint the

database will "hijack" that index instead of creating a new one. You can explicitly create an index

if you so desire.

SQL> CREATE TABLE TEST3

2 (DATACOLUMN NUMBER);

Table created.

SQL>

SQL> CREATE INDEX MYINDEX ON TEST3(DATACOLUMN);

Index created.

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST3';

no rows selected

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST3';

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

MYINDEX NORMAL NONUNIQUE

SQL> DESC TEST3;

Name Null? Type

------------------------------------------------------- -------- ---------------

DATACOLUMN NUMBER

No constraints and only the one index. Add a primary constraint to the table.

SQL> ALTER TABLE TEST3 ADD CONSTRAINT TEST3_PK

2 PRIMARY KEY (

3 DATACOLUMN

4 )

5 /

Table altered.

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST3';

CONSTRAINT_NAME C INDEX_NAME

------------------------------ - ------------------------------

TEST3_PK P MYINDEX

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST3';

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

MYINDEX NORMAL NONUNIQUE

SQL> DESC TEST3;

Name Null? Type

-------------------------------------------------------- -------- --------

DATACOLUMN NOT NULL NUMBER

You can see the index is marked as NONUNIQUE even though there is an obvious primary key on

the table. The index name of the primary key is MYINDEX the index we created on the table. We

can now attempt to insert some bad data into the table.

SQL> INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA;

INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("DBTESTING"."TEST3"."DATACOLUMN")

So the NOT NULL is of course enforced.

SQL> INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA WHERE DATACOLUMN IS NOT NULL;

5 rows created.

SQL> INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA WHERE DATACOLUMN IS NOT NULL;

INSERT INTO TEST3 SELECT DATACOLUMN FROM SOMEDATA WHERE DATACOLUMN IS NOT NULL

*

ERROR at line 1:

ORA-00001: unique constraint (DBTESTING.TEST3_PK) violated

SQL> ROLLBACK;

Rollback complete.

The uniqueness of the primary key is enforced, even though as you can plainly see there is no

unique index on the table. When the constraint is dropped, the index is not dropped as well, but be

careful there is syntax in the drop constraint command to allow the index to be dropped at the same

time.

SQL> ALTER TABLE dbtesting.test3

2 DROP CONSTRAINT test3_pk

3 /

Table altered.

SQL>

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST3';

no rows selected

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST3';

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

MYINDEX NORMAL NONUNIQUE

The constraint is gone, the original index is still there, all is right in the world. Now, some very

thorough person or more importantly a very thorough GUI comes through with that handy right

click drop ability and the results are very disturbing.

SQL> ALTER TABLE TEST3 ADD CONSTRAINT TEST3_PK

2 PRIMARY KEY (

3 DATACOLUMN

4 )

5 /

Table altered.

SQL> ALTER TABLE dbtesting.test3

2 DROP CONSTRAINT test3_pk DROP INDEX

3 /

Table altered.

SQL> SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME FROM USER_CONSTRAINTS WHERE

TABLE_NAME='TEST3'

;

no rows selected

SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME='TEST3';

no rows selected

Conclusion

Every table should have a primary key it is plain good RDBMS design. Be aware of the fact the

database does give you the ability to bypass constraints but still make sure you use constraints in

your system, database referential integrity is the best, it is the fastest and no outside code can be as

efficient as the built in database code. Use the database, we are paying for it and why reinvent the

wheel when it rolls along so nice.

Wow!

That is all I can say and not have content blocked.

The company decided to sell off a small portion to interested buyers. Seems easy enough, every thing is stored in orginisational units, we can shave off that portion, provide it in a easy to load format for the purchasers and we are ready to go, only 5 systems need to have data transferred.. The team of managers and "in the know" people put together to analyse what what was needed said "1 week to develop a plan, another week to extract the data, 1 week of quality control", 3 weeks of work and then all done. We were steaming along steadily well into week two with no major problems, when we started to get calls to our help desk, "Systems is hung", "I can't get logged in".

The help desk guys ran through their normal list of things to check, well, they tried to. Our knowledge base was down, that triggered pretty much every help desk person to pick up the phone and call somebody. Most of the non help desk IT people were in a meeting about the sale and didn't notice anything. It was very funny though, almost like you see in those movies where all of the stars are in a room and all of their cell phones start going off at once to say they had better do something before the world as they know it comes to an end. I was up at the front showing some interesting data I had found in the financials system that was not orginised properly but needed to be extracted when my blackberry started ringing. The IT managers blackberry was vibrating away on the table, and the two SA's cell phones beeping.

After only a few seconds, we all started to file out of the meeting room in a straight line for the server room. I was about 10 feet from the server room at the back of the line, when, wait for it. The fire alarm goes off, the main building fire alarm is whooping and ringing. The hallway to the server room has one of those red fire alarm bells in it. I don't think there was a dry pair of pants in that hallway when that bell went off, those things are freaking loud and the hallway has a door at one end from the lobby and the server room door on the other end, and nothing but concrete, linoleum and at this particular point in time 8 highly trained IT folks to absorb the sound. Despite the fire alarm going off, our manager had been opening the door to the server room and we continue into the server room with the screaming ringing racket of the fire bell going off about 8 feet behind us, as we all came into the server room we found out where the fire that triggered the fire alarm was- in our server room. There was a thick layer of smoke along the roof of the server room and the back of our our tape array rack was billowing smoke, the smell was almost enough to knock one out. Well, being the highly trained IT proffesionals we are, we were stepping on one another trying to get back out of the server room in a mess of arms and legs as 8 of us fit through the standard sized door pretty much at once.

After a very undignified exit into the lobby scaring the people in the lobby pretty much out of their wits we composed ourselves a bit, realized we were still alive and were moving quickly out of the building when one of the SA's spoke up and said "What about the fire suppression system in the room?". My answer, in a moment of pure brilliance at stating the obvious was "It isn't working". We loitered around outside waiting for the billowing smoke to consume the entire building, after what seemed like an hour the fire department showed up. It was really only 7 minutes from the time the alarm went off to the time the FD pulled up. The IT manager and the building manager spoke with the fireman in charge and explained where the fire was.

Us IT folks stood outside with the rest of the building population and waited and wondered. The two SA's were bickering back and forth on who's day it was to send the offsite tapes offsite and wondering if our DR site was in good enough shape to run the company while this place was rebuilt. After another 10 minutes or so the firemen came out and said it was just mostly smoke and they had put the fire out and after a few minutes we can go in and inspect what was up. The building manager would only let one SA and the IT manager into the room for insurance reasons. They didn't touch anything until they had taken about 3,000 pictures and the insurance company over the phone said we could do what was needed to get our business running again.

The Fire inspector figured out what the problem was, it was pretty obvious once you could see it. A power bar that comes built into the rack had ignited into a slow smoldering burn, causing all 8 power cords plugged into it to start to smolder and put off smoke too. It didn't aparranty get hot enough to trigger the fire suppression system in the room. It got plenty hot enough to melt all of the plastic off of all of the power cords, damage the rack and a fibre network hub thing too and generate vast quantities of smoke. All told, under $6,000 dollars damage. Not including the rooms new paint job, contractors to clean the room and the IT departments time to inspect all of the equipment since running it in a smokey environment is apparently bad for it.

The downtime was the remaining portion of the day it happened, and the entire following day but we were up and running at full capacity by 6am on day 3. One of the most junior help desk people we have, a great guy, summed up the entire thing into two words "Mother F***er!" when he was told what was going on. I will let you fill in the bleeped out section.

I promise to post some documentation on primary and unique keys I had been working on later this week. I also have a document on the pitfalls I have ran into using CURSOR_SHARING of SIMILAR or FORCE, but that is a week or two away.



Sunday, October 15, 2006

Well even longer

Still no posts technical or otherwise from me.

Sale is still ongoing and work is mounting. We had a person quit and another go on long term medical leave cutting our team from 5 to 3. That hurt the project and we are now scrambling for consultants who know our apps.

Good news is I got a new laptop, one of those new Dell duo core laptops, the 820 series, 4 gig of RAM and the 15.4 widescreen. It is a bit of a brick to pack around but the 3 hours of battery life and the fact I can put all copies of the databases we are extracting data from on my laptop now and work on the scripts and testing locally is wonderful.


Thursday, September 28, 2006

Long Time

It has been awhile, sorry to all of you.

We just have just sold a small portion of the company and to our surprise, since we haven't done it before, to carve off a section of the company is many times more work than it is to add to the company.


Friday, September 08, 2006

Which SCI FI character

I did the survey and came up with Agent Smith from the Matrix series.
Tom Kyte came up with James T. Kirk.



Which Fantasy/SciFi Character Are You?

The oracle sponge

If you haven't you must read David Aldridge stories of his most recent holiday, you have to read all parts, this link is to part 1.

http://oraclesponge.wordpress.com/2006/09/05/three-days-two-hospitals-part-i/


Wonderfully well written, entertaining and enlightening. Being a ex-motorcycle enthusiast I know exactly what he is talking about.



Monitor Alert Log

UNIX shell script to monitor and email errors found in the alert log. Is ran as the oracle OS owner. Make sure you change the "emailaddresshere" entries to the email you want and put the check_alert.awk someplace. I have chosen $HOME for this example, in real life I put it on as mounted directory on the NAS.


if test $# -lt 1
        then
 echo You must pass a SID
        exit 
 fi
#
# ensure environment variables set
#
#set your environment here
export ORACLE_SID=$1
export ORACLE_HOME=/home/oracle/orahome
export MACHINE=`hostname`
export PATH=$ORACLE_HOME/bin:$PATH

# check if the database is running, if not exit

ckdb ${ORACLE_SID} -s
if [ "$?" -ne 0 ]
then
  echo " $ORACLE_SID is not running!!!"
 echo "${ORACLE_SID is not running!" | mailx -m -s "Oracle sid ${ORACLE_SID} is not running!" "
|emailaddresshere|" 
  exit 1
fi;

#Search the alert log, and email all of the errors
#move the alert_log to a backup copy
#cat the existing alert_log onto the backup copy

#oracle 8 or higher DB's only.
sqlplus '/ as sysdba' << EOF > /tmp/${ORACLE_SID}_monitor_temp.txt
column xxxx format a10
column value format a80
set lines 132
SELECT 'xxxx' ,value FROM  v\$parameter WHERE  name = 'background_dump_dest'
/
exit
EOF


cat /tmp/${ORACLE_SID}_monitor_temp.txt | awk '$1 ~ /xxxx/ {print $2}' > /tmp/${ORACLE_SID}_monitor_location.txt
read ALERT_DIR < /tmp/${ORACLE_SID}_monitor_location.txt
ORIG_ALERT_LOG=${ALERT_DIR}/alert_${ORACLE_SID}.log
NEW_ALERT_LOG=${ORIG_ALERT_LOG}.monitored
TEMP_ALERT_LOG=${ORIG_ALERT_LOG}.temp
cat ${ORIG_ALERT_LOG} | awk -f $HOME/check_alert.awk > /tmp/${ORACLE_SID}_check_monitor_log.log
rm /tmp/${ORACLE_SID}_monitor_temp.txt 2>/dev/null
if [ -s /tmp/${ORACLE_SID}_check_monitor_log.log ]
   then 
     echo "Found errors in sid ${ORACLE_SID}, mailed errors"
     echo "The following errors were found in the alert log for ${ORACLE_SID}" > /tmp/${ORACLE_SID}_check_monitor_log.mail
     echo "Alert log was copied into ${NEW_ALERT_LOG}" >> /tmp/${ORACLE_SID}_check_monitor_log.mail
     echo " "
     date >> /tmp/${ORACLE_SID}_check_monitor_log.mail 
     echo "--------------------------------------------------------------">>/tmp/${ORACLE_SID}_check_monitor_log.mail
     echo " "
     echo " " >> /tmp/${ORACLE_SID}_check_monitor_log.mail 
     echo " " >> /tmp/${ORACLE_SID}_check_monitor_log.mail 
     cat /tmp/${ORACLE_SID}_check_monitor_log.log >>  /tmp/${ORACLE_SID}_check_monitor_log.mail

 cat /tmp/${ORACLE_SID}_check_monitor_log.mail | mailx -m -s "on ${MACHINE}, MONITOR of Alert Log for ${ORACLE_SID} found errors" "
|emailaddresshere|" 

     mv ${ORIG_ALERT_LOG} ${TEMP_ALERT_LOG}
     cat ${TEMP_ALERT_LOG} >> ${NEW_ALERT_LOG}
     touch ${ORIG_ALERT_LOG}
     rm /tmp/${ORACLE_SID}_monitor_temp.txt 2> /dev/null
     rm /tmp/${ORACLE_SID}_check_monitor_log.log 
     rm /tmp/${ORACLE_SID}_check_monitor_log.mail 
exit
fi;

rm /tmp/${ORACLE_SID}_check_monitor_log.log > /dev/null
rm /tmp/${ORACLE_SID}_monitor_location.txt > /dev/null


The referenced awk script (check_alert.awk). You can modify it as needed to add or remove things you wish to look for. The ERROR_AUDIT is a custom entry that a trigger on DB error writes in our environment.



$0 ~ /Errors in file/ {print $0}
$0 ~ /PMON: terminating instance due to error 600/ {print $0}
$0 ~ /Started recovery/{print $0}
$0 ~ /Archival required/{print $0}
$0 ~ /Instance terminated/ {print $0}
$0 ~ /Checkpoint not complete/ {print $0}
$1 ~ /ORA-/ { print $0; flag=1 }
$0 !~ /ORA-/ {if (flag==1){print $0; flag=0;print " "} }
$0 ~ /ERROR_AUDIT/ {print $0}
  




I simply put this script into cron to run every 5 minutes passing the SID of the DB I want to monitor.

Monday, September 04, 2006

SQL*plus in windows

As you probably know from reading my blog, I don't like windows. I know how to use windows. I use windows, I have had the misfortune of administrating databases on windows, and most of our applications are made to run on windows. Windows runs the world from the everyday user.


I have windows on my laptop, but I have as little as possible running on windows and pretty much my first task in the morning is to startup my SUSE vm client on my laptop and work from there. This is of course resource intensive and with only having a D600 with the possibility of flaming batteries, resources are scarce. There are times on my 1.3ghz w/1 gig of ram laptop I am trying to run 3 oracle databases, 1 EE for windows, 1 EE for Suse in a VM client,and 1 SE for Suse in a VM client. When I do that, lets just say my laptop has difficulties keeping up with the simplest tasks, like keeping the clock in the taskbar up to date.

I was reading one of the threads going on flaming XE at Doug Burns blog -An Oracle XE user speaks and checked out the link from William Robertson. William Robertson is now my hero. I knew the capabilities existed, I had set up things like this for users. But I had never thought of doing something this simple for myself. I am talking about his wonderfully in depth but amazingly simple to do article on setting up SQL*plus on windows . I immediately went a head and configured up my windows sqlplus as he has explained.

Man... it is sometimes amazing how much the simple little things can make your life so much easier.

Oh, and for those of you waiting for an update. The fellows did their duty and dressed as described in earlier posts. I have requested pictures and I have been assured I will receive them shortly. I will of course post them as soon as I can. I was told, it was a banner day at the office, everybody that could be at the office was at the office.