Wednesday, January 7, 2009

How to deploy files in a remote server?

It's easy you say, just share your drives when you connect through rdp --> http://technet2.microsoft.com/windowsserver/en/library/f47ce263-f72e-469d-bf14-6605b7f4cce51033.mspx?mfr=true. Ok, let's talk about worse case scenario, you can't share drives and you can even share a drive from your remote server.
So you can use a very usefull tool named WordPad --> http://en.wikipedia.org/wiki/WordPad. Surprised ?
It's even easier than sharing you drives, watch it :

  1. Zip all your files into a single file;
  2. Open a wordpad in your local machine;
  3. Copy zip file into wordpad (WordPad would serialize your file);
  4. Copy object that appears inside Wordpad;
  5. Open wordpad in your remote machine and paste your object into it;
  6. Finally copy your recent pasted object into remote server.

Enjoy.

Oracle : Reduce your parsing times

All the queries that you execute in an Oracle database are parsed and then executed. However, is a nonsense(and a time wastefulness) to parse over and over the same query, even if executed by different users.

So, to avoid this, Oracle uses a 'Shared pool' area where all the cursors are cached after being parsed.

How it works? It's easy:

  1. Your query is hashed;
  2. Oracle searchs shared pool for the matching hash value;
  3. Is it there? If so, execute the cursor;
  4. Otherwise parse your query, hash it and put it in shared pool for future executions;

To take advantage of this feature of Oracle engine, we have to take care for:

  1. Hashing is executed over all your query, so Case is important.

Select * from emp is different from Select * from EMP and therefore you will not take advantage of shared pool in your second execution; So, it's important that your developers team agree in Naming and Case conventions to take greater advantage of Oracle Shared Pool.

  1. Where clauses are hashed too;

Select * from emp where emp_no = 1 is different from Select * from emp where emp_no = 2, use global variables and procedures whenever you can.

If you follow this rules, you will not solve all the performance problems from your application but will give a little step toward the perfection.

Oracle : SQLCODE and SQLERRM in Inserts

Today I came across an unexpected problem when executing an exception block inside a procedure :

My code was something like this :

insert into dc_errors (error_message,error_date) values (SQLERRM, SYSDATE);

and I allways obtain an annoying PL/SQL: ORA-00984: column not allowed here.

To solve this problem I've changed my code into :

v_exception := substr(SQLERRM, 1, 256);
insert into dc_errors (error_message,error_date) values (v_exception, SYSDATE);


with v_exception as varchar2(256) .

SQL * Plus Tip - 1

To change the previous query, just type EDIT, this command will redirect you into an editor so you can edit previous SQL command, short name : ED.

Then type / and the new SQL command will be executed

Oracle : Reducing join execution time

After executing a join over two tables, whith 4 million rows each and indexes in join columns, I realized that 4 minutes it's too much time waiting for results. So I decided to watch for the execution plan :

select columns from tableA join TableB on tableA.id = tableB.id

Execution Plan----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE
1 0 FILTER
2 1 SORT (GROUP BY)
3 2 TABLE ACCESS (BY INDEX ROWID) OF 'TABLEA'
4 3 NESTED LOOPS
5 4 TABLE ACCESS (FULL) OF 'TABLEB'
6 4 INDEX (RANGE SCAN) OF 'TABLEA_U1' (UNIQUE)

All seems to be correct, after all I'm using Rule Base Optimizer. In order to reduce execution time I force the execution of an hash join instead of a Nested Loops.
Execution time droped to about 2 minutes and execution plan looks like this :

Execution Plan----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE (Cost=624 Card=40000 Bytes=2 800000)
1 0 FILTER

2 1 SORT (GROUP BY) (Cost=624 Card=40000 Bytes=2800000)
3 2 HASH JOIN (Cost=172 Card=40000 Bytes=2800000)
4 3 TABLE ACCESS (FULL) OF 'TABLEA' (Cost=35 Card=2000 Bytes=62000)
5 3 TABLE ACCESS (FULL) OF 'TABLEB' (Cost=136 Card=2000 Bytes=78000)

And all I've to do is change my query to :

select /*+ USE_HASH (tableA tableB ) */ columns from tableA join TableB on tableA.id = tableB.id

Why is this happening? why RBO this choose this plan? The answer is simple, RBO doesn't consider hash joins has a valid execution path, so you have to force it.
This specific join is used when a large amount of data needs to be joined or when a large fraction of the the table needs to be joined, however this is a very memory expensive operation and need to be carefully analised.

PL/SQL Tip - 1

Query v$parameter view for BD parameters checking.
In this example I'm looking for the selected optimizer mode.

select value from v$parameter where name = 'optimizer_mode';

Enjoy.

PL/SQL : Show locked objects

Today, after trying unsuccessfully to drop my temporary tables, and subsequent fails due to object locks, I tried to find who's locking my table.
Not an easy task, so I dig a little and found this amazing script that solved my problem. If you have the same problem, read here --> http://www.orafaq.com/scripts/performance/lockall.txt how to list all locked objects.

PL/SQL : How to update using select

This "problem" came across me when I needed to update an entire temporary table column. One option is to loop all table rows, boring and time consumer task. After some background searchs I've adopted this method:

UPDATE TABLEA SET
(TABLEA.COLUMNA, TABLEA.COLUMNB) =
(SELECT TABLEB.COLUMNA, TABLEB.COLUMNB FROM TABLEB WHERE TABLEB.ID = TABLEA.ID)

I've basically do one inner select and join the two tables in the inner select's WHERE clause.

EIM : Shell execution order

When running an EIM process with a shell type process section, it will be executed from top to bottom. In this example, first process to run will be Assess followed by Contact.

[Siebel Interface Manager]
PROCESS = P1
USER NAME = "XXXX"
PASSWORD = "XXXX"

[Lancar]
TYPE=SHELL
INCLUDE = "ASSESS"
INCLUDE = "CONTACT"

[CONTACT]
TYPE = DELETEBATCH = 3999
TABLE = EIM_CONTACT
ONLY BASE TABLES = S_PARTY,S_CONTACT
DELETE MATCHES = S_CONTACT, (COLUMN= 'DELETED')

[ASSESS]
TYPE = DELETE
BATCH = 3998
TABLE = EIM_ASSESS
ONLY BASE TABLES = S_ASSESS,S_ASSESS_VAL
DELETE MATCHES = S_ASSESS, (COLUMN = 'DELETED')

PL/SQL : Scripting for table drop

I came from MS SQLServer and I miss a lot of nice functionalities, like for instance, If exists.
Why am I talking about this? Simple, I want to run a script that "only" drops a few tables that I'don't no if they already exists.

Easy to say, hard to find. So here's a script for doing that, without returning any errors.

set echo off;
set heading off;
spool run.sql;
select 'drop table 'table_name';' from dba_tables where UPPER(table_name) in ('TABLEA', 'TABLEB', 'TABLEC');
spool off;
@run.sql;

Enjoy.

EIM : DUP_RECORD_EXISTS after Update

This status happens after running an EIM update process with lines that match exactly the lines being updated in base table.

Localcooling . com


Download the 100% Free LocalCooling Application and it automatically optimizes your PC's power consumption by using a more effective power save mode. You will be able to see your savings in real-time translated to more environmental terms such as how many trees and gallons of oil you have saved.


Local Cooling will:

  • Cut your energy bills.
  • Reduce the amount of Greenhouse Gas CO2 emissions as a result of your reduced PC power consumption.
  • Give you full control over your power mode settings.
  • Improve your overall computing experience and efficiency.
  • Show you in detail how much you have saved since installing the software.
Learn more -> http://www.localcooling.com/about the LocalCooling Application and how it will help you save energy!

How to relate a contact whit their accounts

Contact accounts can be found in S_PARTY_PER intersection table. This table relates person_id column (par_row_id from s_contact) with party_id column (par_row_id from s_org_ext). Both person_id and party_id are foreign keys from s_party.

PL/SQL : Check script for object owners

In real life development environments, you develope a script logged as UserX, and someone in Support Team will install it in production environment logged as UserZ.
So far, nothing unusual happens. But, if we are talking about oracle scripts, there's something that you have to deal with, Schemas, If you didn't reference all you objects with full name, SchemaX.TableA for instance, when UserZ tries to install it, he will not find TableA in is schema.

In simple scripts, with few lines, it's easy to manually check for errors, but try to do it in a scripy with thousand of lines...

So I've developed this procedure to "parse" my code looking for this kind of errors

FUNCTION CHECK_OWNER_IN_SQL(
p_list varchar2,
p_del varchar2
) return boolean
is
l_idx pls_integer;
l_list varchar2(32767) := p_list;
l_value varchar2(32767);
keyword varchar2(10000);
existsObject integer;
result boolean;
begin
result := false;
loop
l_idx := instr(l_list,p_del);
if l_idx > 0 then
keyword := substr(l_list,1,l_idx-1);
select count(*) into existsObject from user_objects where lower(object_name) = lower(keyword);


if existsObject > 0 then
DBMS_OUTPUT.Put_Line( 'Possible error in ' keyword);
result := true;
end if;

l_list := substr(l_list,l_idx+length(p_del));
else
keyword := l_list;
select count(*) into existsObject from user_objects where lower(object_name) = lower(keyword);

if existsObject > 0 then
DBMS_OUTPUT.Put_Line( 'Possible error in ' keyword );
result := true;
end if;
exit;
end if;
end loop;
return result;
end;




--Possible values for p_type are :
-- DATABASE LINK,FUNCTION,INDEX,PACKAGE,PACKAGE BODY,PROCEDURE,SEQUENCE,SYNONYM,TABLE,TRIGGER,TYPE,VIEW


PROCEDURE CHECK_OWNER(
p_owner IN varchar2,
p_type IN varchar2,
p_name IN varchar2,
p_sql IN varchar2 := NULL
)
IS
cursor lines
is
Select text from all_source where lower(owner) = lower(p_owner) and lower(type) = lower(p_type) and lower(name) = lower(p_name) order by line;
sqltext varchar2(32000);
result boolean;
linha integer;
begin
if p_sql is not null then
result := siebel.check_owner_in_sql(p_sql , ' ');
else
linha := 1;
for line in lines loop
sqltext := TRIM(line.text);
IF substr(sqltext,1,2) <> '--' then
if siebel.check_owner_in_sql(sqltext , ' ') then
DBMS_OUTPUT.Put_Line( 'Linha ' linha ': ' sqltext);
end if;
end if;
linha := linha + 1;
end loop;
if linha = 1 then
DBMS_OUTPUT.Put_Line( 'Não foi encontrado o objecto a validar');
end if;
end if;
end;


After create this two procedures, you have only to execute the last one, and watch for possible warnings in your output window.

SQL Navigator : Code Templates

After trying for a while to use SQL Navigator from Quest --> http://www.quest.com/sql-navigator/ to develope my pl/sql procedures and queries, I've found a new (for me) feature : Code templates. Tired of write allways the same kind of code structures ? Use code templates. How? It's easy. Just take a look at this help page from navigator help. (As a good developer that I am, I never read help files).


You can program Key combinations from "Ctrl+Shift+A" to "Ctrl+Shift+Z" with text up to 255 characters in length.
To program shortcut keys

  1. From the View menu, choose Preferences.
  2. Under the Code Editors preference heading, expand General, and then scroll down to the Templates category.
  3. Where you see the words , click and then view or change shortcut key assignments as required.


Try it, and watch your development times drop a little bit !!!

S_POSTN_CON : Description

This table associates a contact with positions that can acess it. This relation is suported by column con_id (par_row_id from s_contact) and postn_id (row_id from s_postn).
This is a many-to-many relationship : A contact can have more than one position associated, and a position can be related with multiple contacts.
Keep in mind that con_id is foreign key from s_party.

Joins : Please talk ANSI SQL with me.

People, who had to port a Microsoft SQL Server or Access database over to Oracle, know what I'm talking about. This article --> http://certcities.com/editorial/columns/story.asp?EditorialsID=106 show us a good example of ANSI SQL joins and also show us a few good reasons why we should use ANSI join syntax instead of classic and specific join syntax :


    1. You don't need to specify the join condition in a natural join;
    2. You can do more with ANSI SQL join syntax than with classic Oracle syntax;
    3. There is no performance penalty;
    4. In the long run you will see more of it, and less of the older syntax;
    5. It's portable;
    6. It's easier to understand what is happening .

Bottom line is :

So join me in creating portable SQL joins that are easy to read, do more than you can with Oracle syntax, and don't slow you down.

WHy MINUS does NOT EXISTs in our queries?

Read this great (and old) article --> http://www.oraclemagician.com/mag/magic8.pdf about MINUS vs NOT EXISTS operators.


There really isn’t just one right way to design queries. In some cases, you really are better off using Not Exists. In many cases, however, you should use the set operator MINUS. Once you understand the principles, you can easily choose the best method for your particular case.

Get last file version

Imagine this situation:

  1. You have two package P1 and P2 in the same stage, and both P1 (who is to be installed first) and P2 have an attached file F1;
  2. In P1 the F1 file is in version 1, but in P2 is in version 3;

When I try to execute P1 and I try to get F1 file, Harvest return me F1 in version 3, when it has supposed to return version 1 of the file.

So take care when promoting 2 or more packages, to the same stage, with different version of the same file. Harvest only get the last version of it, regardless what version you included in your package.

Debugging in http://localhost:8082

Today I've made my first siebel project compilation, all my environment is brand new and well configured.
I've enabled 'Auto-start web client' feature and hit the road. IExplorer browses http://localhost:8082/ and inherent error. Why in God's name is this happening?

The answer is simple, (If my friend Alexandre didn't help me, it wouldn't be so simple), my Firewall is enabled.

After I disabled that, my debug can go on!!

Error 452: Match column X not found in Y

Today I had to create a new column in EIM_CONTACT table, to build a new attribute mapping for deletion purposes. All went fine until I test my EIM task.

Error 452: Match column X_COLUMN not found in S_CONTACT.

I run trough all my steps to find what's wrong in it. All seems to be in perfect shape. My next step was to loose some time reading bookshelf and Siebel support SR's. Nothing came across that helped me to solve my problem.

Last step in problem resolution algorithm, ask for help. Allways work!!

My colleague João had the solution, Siebel caches EIM mappings in \siebsrvr\BIN\diccache.dat, all we have to do is delete this file and Siebel will build a new one for you (with your new mappings).

Finally, I successfully ran my EIM process.
All Rights Reserved