Jul 2, 2012

Upgrading 11.2.0.2.0 to 11.2.0.3.0

As Oracle changed upgrade approach (now recommended Out-of-place upgrade), I would put those quick steps here how I did that -


1. Go to the document ID 730365.1 in My Oracle Support (MOS). Go to the link "11.2.0.x.x TO 11.2.0.3.0"

2. Download Patch:10404530

3. Download pre-upgrade utility script utlu112i_5.sql. MOS document ID 884522.1

4. Run utlu112i_5.sql as sysdba

5. Resolve the warnings

6. Gather dictionary stats with "exec dbms_stats.gather_dictionary_stats;"

7. Go to the new installation downloads and run installation

8. Specify “Install Database Software only” and point to a new oracle home – for example /oracle/app/oracle/product/11.2.0/dbhome_2

9. Run through the rest of the installation. Run the root.sh at the end as root user.

10. When finished, set the environment variable for new home -
$export ORACLE_HOME=/oracle/app/oracle/product/11.2.0/dbhome_2
$export PATH=$ORACLE_HOME/bin:$PATH

11. Now run the upgrade -
$ which dbua
$/oracle/app/oracle/product/11.2.0/dbhome_2/bin/dbua

12. Dialogue will ask which db to upgrade. Select the db and click Next

13. Verify oratab content. This may be located in /var/opt/oracle/oratab or /etc/oratab

14. Check the latest version with select * from v$version;


***

Jun 1, 2012

Concurrency waits analysis - a case of our production system

We have been experiencing shared pool concurrency issue (mostly "library cache: mutex x") now a days. Ones again everything slowed down for such shared pool concurrency waits. There were no single/particular SQLs which caused this. I see a number of things which contributing to this concurrency problems from time to time. Here is the descriptive presentation -

1. There is an insert SQL on a table. Most of the times (almost every time I look at production during peak hours), we see a shared pool concurrency waits ("library cache: mutex x") on this statement. I did a lot of research on this to understand whether this is because of us for doing something wrong. Oracle made the mutex almost a black box for outsiders. Using web resources, I managed to dig to some extent from some internal details (mutex sleep history, mutex ASH history etc). I found, sometimes it shows the waits are on the sequence we use in this SQL, and sometimes it is not understandable - the mutex sleep locations are basically Oracle code internals. Probably we hit the bug on this - "Bug ID 12819613: HIGH CURSOR: MUTEX S AND LIBRARY CACHE LOCK WAITS" or something similar - there are tons of mutex bug reported to Oracle support.

Related article: http://andreynikolaev.wordpress.com/2011/05/01/divide-and-conquer-the-true-mutex-contention/#comment-343 - I also shared our problem with the writer (who is an expert on mutex problems) in comment section.

Action Items:


- We could contact Oracle Support for their opinion.
- We could drop the ID column which we don't need now and get rid of the waits on sequence.
- We batch the inserts so that it does a bulk of inserts and does not require soft parse again and again.

2. Sometimes, there are random types concurrency waits pops up. There are no fixed pattern for this or no fixed set of SQLs which contributes to this particularly. Here, the important thing is, during this time, hard parse increases in database (around 2%, normal figure is around 0.5%). This stress out shared pool memory and resources, finally slows down everything a little bit as the waits are inside shared pool. These are all years old SQLs.

Action Items:


- We need to reduce hard parse for those SQLs. We have identified some SQLs we need to look again and find a way to use bind values. Sometimes it's not possible to use bind values inside "IN clause" as the number of parameters varies for user inputs.

3. We do a lot of soft parse. The "execute to parse" ratio is very poor. This might happen for a typical web application where we can't always use statement caching. Too many soft parses are also expensive and stress out shared pool for big applications.

Action Items:
- I don't know exactly what we could do in short term. May be in future we can do it in a better way when we use some better programming model (with JSF and JBoss Seam) - we are on that direction.


- We had problems few years back when we tried to use statement caching in our application. So far we remember, it consumed huge memory and bogged down the system. However, we can do some testing again and see what is the behavior for a small number of statement caching.

4. We have another insert SQL. This statement consumes the highest amount of shared pool memory. This is because, here we are not able to reuse cursors even though we use bind variables and thus produces a huge number of child cursors. During yesterday problem, the number of child cursors were 1351. My understanding is, the main problem with this SQL - there are bind mismatch in most cases when the SQL comes into database for an execution with all its 42 bind variables. Producing so many child cursors (and searching within the list) causes shared pool mutex waits. This is an issue with 11g where database does not automatically obsolete a parent cursor "anymore" when it reaches 1024 child cursors.

Related article: http://www.usn-it.de/index.php/2010/08/04/oracle112-mutex-s-too-many-child-cursors

Action Items:


- As I saw the reason for generating so many child cursors was for bind mismatch, I think, we need to change the jdbc prepared statement coding and need to use "java.sql.Types" to set nulll values so that it understands the bind type and doesn't create a child cursor for type mismatch caused by setting 'null' explicitly.


For example, for a column we use - preparedStatement.setObject(
index++, record.getAdministeredBy() != null ? record.getAdministeredBy().getId() : null);


We need to program like "preparedStatement.setNull(index++, java.sql.Types.INTEGER);" when the object is null so that the cursor understand the datatype for the bind variable.


I have talked to the programmers to make the changes. There are few other queries like this producing high number of child cursors - but those are not that severe, anyways.


- Another thing we could do now for the time being using a scheduled job periodically, we could purge the particular cursor when it produces many child cursors (say more than 100). This will keep the child cursor list short and reduce the waits on that sql when it searches through so many child cursors for bind matches. 

These were my assessments for the database.

***

Oct 30, 2011

Monitoring long running SQLs

When we moved to new box after upgrading the h/w - we had been seeing some of the queries taking more than normal time to finish up. Sometimes, those were ended with a blocking status.

When the ops team noticed high jdbc usage and informed me, that was too late. The customers were suffering much earlier than we get noticed. The first incident happened around 5 pm, jdbc usage shown up high on "cacti" and "Nagios" a bit later, and I got call around 5:30 pm (my time 3:30 am) , by that time the system was almost bogged down.

Anyways, to get an early notification, I write a shell script and put it in cron job which will run the script in every 5 minutes. This will check long running queries (running for more than three minutes) and mail to ops team so that we can take precaution and prevent from any possible system failure.

Here is the SQL script I used in my shell script -

set linesize 200
set pagesize 200
col "SQL Text" format a40


SELECT a.username "User", a.sid "SID", a.serial# "Serial"
, b.sql_text "SQL Text", a.last_call_et "Elapsed Time"
FROM v$session a, v$sql b
WHERE a.sql_id = b.sql_id
AND a.status='ACTIVE'
AND a.LAST_CALL_ET >= 180
AND a.USERNAME IN ('PROTS','STEE');


***

Disabling an application feature with database trigger

Interesting things have been happening around but I did not write down here for quite sometime.

I remember the incident - I got call around 3 am from the ops team when they noticed very high jdbc connection usage. I found that, one of our delete feature taking too much time in db and also causing others to be blocked.

This 'delete' is not such an important feature and we had been thinking to get rid of this permanent delete from database. We had been thinking not to delete any user permanently from database because, we are no longer running a small system. We have FK reference over thousand places in database. A permanent delete checks all the FK references in child tables, anyways. This takes a lot of time even though FK references were indexed. Till then, unfortunately we could never find a suitable window to do the release with the fix. The alternatives was - changing the user status to "deleted" by a flag.

Anyways, the flag change approach requires some programming time and a release schedule, which was not going to happen in a day or two even if we had been locking by this delete that night. User complaining slowness...

I thought, as a quick fix, I can put a trigger and prevent user from using that feature - I mean it's possible to stop user from deleting the records from that table.


CREATE OR REPLACE TRIGGER PREVENT_USER_DELETE
BEFORE DELETE
ON app_user
FOR EACH ROW
BEGIN
RAISE_APPLICATION_ERROR(-20005,'User delete is temporarily unavailable');
END;
/


This simple trigger was a life saver that night. Few users who tried to delete application user permanently, they received application error page though, but the db never got locked in this cascading effect. This bought us some time to improve the feature of permanent delete - changing status flag.

***

Oct 12, 2011

Flashback database feature speed up migration script testing

Usually people use flashback database technique to recover fast from data loss or corruption. This is much faster approach than the traditional point-in-time recovery where redo and archive logs are being used.

We did find it useful that helped in testing migration scripts during big application release. We had to do this on real data. There were huge data changes/manipulations in several tables on different schemas. After migration, if anything discovered wrong later in testing phase, we had to start the whole thing with a fresh schema. The schema loading time was huge to start over where flashback technique just rewind the whole database in just 30 min. 

Here are few quick steps to configure flashback database feature -

1. Setting initialization parameters -

alter system set db_recovery_file_dest_size=100G;
alter system set db_recovery_file_dest='/oradata/flashback';
alter system set db_flashback_retention_target=
4320;

2. DB in archive log mode -

select log_mode,flashback_on from v$database;
alter database archivelog;


3. Enabling flashback logging -

shutdown immediate
startup mount
alter database flashback on;
alter database open;


4. Checking status -

select flashback_on from v$database;
select * from v$flashback_database_log;

 
5. Creating restore point before running migration scripts -

create restore point before_migration_91;
select systimestamp from dual;


6. Performing migration/DML scripts, java programs etc.

When needed, we re-winded the database (to a fresh copy) using the following command -

We can lookup the already created restore points like below -

SELECT NAME, SCN, TIME, DATABASE_INCARNATION#,
GUARANTEE_FLASHBACK_DATABASE,STORAGE_SIZE
FROM V$RESTORE_POINT;

Putting database in mount state - 

flashback database to restore point before_migration_91;
alter database open resetlogs;
 
The commands below could be used as well - 

flashback database to timestamp to_timestamp('22-JUN-11 10:30:00','DD-MON-YY HH24: MI: SS');
flashback
database to scn scn_no;


That made the whole migration testing a lot easy and fast if we had to start over from the begging with fresh schemas.
***

Jul 17, 2011

Making system generated primary key for replication ease

It is highly recommended to have a Primary key or Unique key on each table for GoldenGate replication. There are cases where in relational table, we don't have such a key. The workaround is simple - just add a system generated key as default value.

Example below -

CREATE TABLE LIMITATION  
(  DETERMINATION_ID NUMBER(19,0) NOT NULL,
    LIMITATION VARCHAR2(300 CHAR),
    ID VARCHAR2(32 BYTE) DEFAULT sys_guid(),
     PRIMARY KEY ("ID")

);


The technique was very helpful when we found a couple of tables missing the PK/UK requirements just before a big release!

***

Nov 29, 2010

Oracle Text Search - Index tuning for handling HTML content

We used Oracle Text Search in our web application for a secure messaging module years ago. Recently, when we added rich text formatting in that module, we discovered that Text Search feature was not working correctly because of the html tags inside the clob content.

So, we had to fix the thing to make that workable again. Basically, we added few parameters while creating the index to handle html properly.


--old
CREATE INDEX "MSG_CONTENT_TEXT_I" ON "MESSAGE_CONTENT" ("CONTENT") INDEXTYPE IS "CTXSYS"."CONTEXT";

--corrected one
CREATE INDEX "MSG_CONTENT_TEXT_I" ON "MESSAGE_CONTENT" ("CONTENT") INDEXTYPE IS "CTXSYS"."CONTEXT" PARAMETERS ('FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP');


Where,
* NULL_FILTER: No filtering required. Use for indexing plain text, HTML, or XML documents.
* HTML_SECTION_GROUP: Use this group type for indexing HTML documents and for defining sections in HTML documents.

Life is good again!

Here is a good document for reference-
http://download.oracle.com/docs/cd/B19306_01/text.102/b14218/cdatadic.htm