dbms_session.close_database_link in oracle procedures - oracle

I have many procedures for which i am using the same db link and this procedure can be executed at different time or some of the procedure runs at the same time depending on the scheduler job. This procedure used to fetch the data from remote database and insert the data in my local database. As i dont want to left open the db connection after execution of every procedure because it produces the load on the database connection which might impact on query cost and query execution time. Thats why i am using dbms_session to close the database link at the end of each and every procedure.
DBMS_SESSION.CLOSE_DATABASE_LINK
But i dont know whether this results any issue while fetching the data for some of the procedure which executes at the same time. As the dbms session close the db link connection for some of the procedures and at the same time if any of the procedure try to acess the db link and it might not fetch the data or results in any error. Will this situation arises while using
DBMS_SESSION.CLOSE_DATABASE_LINK ?

Following are the ways links could be closed:
A. Only session which opened the database link can close it..
Database link are closed when the session is closed...
select * from dba_DB_LINKS will show database links created
V$DBLINK will lists all open/active database links in your session,..
For an indication on how long the dblink has been open, run:
select t.addr, s.sid, s.username, s.machine, s.status,
(sysdate - to_date(t.start_time, 'MM/DD/YY HH24:MI:SS')) * 24 as hours_active
from v$transaction t, v$session s
where t.addr = s.taddr;
How to know if a transaction is local or distributed?
Check v$global_transaction
B. Using ALTER SESSION or explicitly using command:
alter session close database link <name>;
or use the following package:
dbms_session.close_database_link(<name>);
C. It is also posible to set idle_time limit to user under which connects dblink.
On the server side of dblink (target of dblink) issue:
create profile pidle limit idle_time 5; -- 5 minutes
alter user test profile pidle; -- user under which connects dblink
alter system set resource_limit=true; -- must be set to work idle_time limit
(or add resource_limit=true to init.ora or both)

Related

tracing all SQL queries which have executed when application fire an order

I need to collect all the SQL queries (SELECT, UPDATE, DELETE, INSERT) which have been used by the application when any order is processed through the application.
If I can get all SQL's for atleast 50 orders processed through the application then I can check that which SELECT, UPDATE, DELETE statements are frequently in use and which tables are being frequently used by the application after finding these information.
I can get to conclusion that on which table I can use partitioning as if I get the whole SQL's with the WHERE clause I can also get to know that which type of partitioning will be better for any particular table and the partitioning.
However it seems to be a hectic exercise as there could be lots of SQL's which the application use but it helps me understand the application and also after this exercise i will be having a scrutiny report of my application behavior with database which can be used by the later employees.
For this till now i have used the DBMS_adivsor package which gives me some tables of my database to be partitioned and when i check the EXPLAIN PLAN of SQL which i used in the DBMS_ADVISOR then it occur to me that tables which are being full table scan in EXPLAIN PLAN the DBMS_ADVISOR told me to partition them.
The thing is that i can not partition the tables based on this information as its a application level partitioning and also my manager will be not convinced by this little information. so i have come up with the ABOVE plan:(
I need to do this to find out the tables where i can perform table partitioning and other performance tuning things like creating index's as i can get the where clause with filter so its like a database tuning and i want to do this as it will help me grow my career in database development.
Please help me out with this scenario.
Will this query give me required information !
select st.command
from V$SQLTEXT_WITH_NEWLINES st, SYS.V_$SQL s
where st.hash_value = s.hash_value
and parsing_schema_name = 'NETSERVICOS2CM'
and s.module = 'JDBC THIN CLIENT';
Tracing for non-dba USER's ----
GRANT SELECT ON SYS.V_$SESSION TO USER;
GRANT SELECT ON SYS.V_$MYSTAT TO USER;
To get the SID and SERAIL#
SELECT sid, serial# FROM SYS.V_$SESSION
WHERE SID = (SELECT DISTINCT SID FROM SYS.V_$MYSTAT);
Then on DBA user execute this --
EXEC DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION (sid=>3002, serial#=>31833,sql_trace=> true);
OR
on no-dba user i am using --
ALTER SESSION SET SQL_TRACE = TRUE;
OR
EXEC DBMS_SESSION.set_sql_trace(sql_trace => TRUE);
Trigger to trace a session for a particular user ----
CREATE OR REPLACE TRIGGER ON_MY_SCHEMA_LOGIN
AFTER LOGON ON DATABASE
WHEN ( USER = 'NETSERVICOS1CM' )
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET TRACEFILE_IDENTIFIER = "net1cm"';
EXECUTE IMMEDIATE 'alter session set statistics_level=ALL';
EXECUTE IMMEDIATE 'alter session set events ''10046 trace name context forever, level 12''';
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
After that to stop trace i am using
ALTER SESSION SET EVENTS '10046 trace name context off';
ALTER SYSTEM SET EVENTS '10046 trace name context off';
As suggested by Derek.
After this you may have multiple trace files to make a consolidate trace file we can use TRCSESS utility --
trcsess output=net1cm_trcsess.trc module="JDBC Thin Client" *net1cm.trc
It will create a single trace file net1cm_trcsess.trc for all trace file generated in my case (with trace file identifier net1cm).
Now we can use TKPROF utility to generate a report which is in human readable form using below command for example ---
tkprof net1cm_trcsess.trc OUTPUT=net1cm_trcsess.txt EXPLAIN=netservicos1cm/netservicos1 SYS=NO
Thanks
So here is my advise.
You can use several different traces for application context actions, such as INSERT, DELETE, UPDATE, SELECT, or even all actions.
Say you have a PL/SQL program run by an application, or have an OCI call to the database. You would have this oracle code at the module/stored proc level:
dbms_application_info.set_module(<module_name>,'execute');
before you execute the entire code. (After the BEGIN in the code).
or
dbms_application_info.set_module(<module_name>,'UPDATE');
before you do an update SQL statement.
To turn off application context, you would use (before the END;):
dbms_application_info.set_module(NULL,NULL);
Then when you execute the module or run the update statement you would like to trace in the module you would make sure you did this prior to and after the module runs
execute DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE( -
service_name => '<service_name>', -
module_name => '<module_name>', -
action_name => DBMS_MONITOR.ALL_ACTIONS, -
waits => TRUE, -
binds => TRUE);
All actions would be traced and you would know exactly where the statement ran and what action was executed.
To turn it off:
execute DBMS_MONITOR.SERV_MOD_ACT_TRACE_DISABLE( -
service_name => '<service_name>', -
module_name => '<module_name>', -
action_name => DBMS_MONITOR.ALL_ACTIONS);
To do this at the session level, you would do the following when 9 is the serial number and 100 is the Sid, for example. (check the syntax).
execute DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(9,190,TRUE);
To turn it off:
execute DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(9,190,FALSE);
At the database level, (You have to be very careful with this because it will generate a trace for the entire database and can fill up your diagnostic directory on your oracle database. Disclaimer: USE WITH CAUTION).
execute DBMS_MONITOR.DATABASE_TRACE_ENABLE(waits=>TRUE, binds=>TRUE, instance_name=>'<Instance_name>');
execute DBMS_MONITOR.DATABASE_TRACE_DISABLE(instance_name=>'<instance_name>');
You can leverage v$sqltext_with_newlines ,V$SESSION and v$session_longops. You can google with these words and see if these can be useful for your requirements.

Calling a function on a remote database requires commit. SQL Developer

I have a requirement to call a function on a remote database (defined by a public database link) within a query. Everything works as expected except that when selecting "Disconnect" from the local database connection in SQL Developer it brings up the dialog:
Connection "localDB" has uncommited changes....
even though the remote function only reads from tables, and the invoking query isn't an update / insert / delete. I'm concerned that using this architecture may cause problems in the future where uncompleted transactions on the localDB diminish resources.
Have tried using the "PRAGMA AUTONOMOUS_TRANSACTION;" instruction in the remote db but to no avail. Any suggestions?
The following demonstrates the behaviour I'm experiencing:
RemoteDB function:
create or replace
FUNCTION FN_test (inempid in number) RETURN varchar2 is PRAGMA AUTONOMOUS_TRANSACTION;
sReturn varchar2(20);
BEGIN
sReturn:=to_char(sysdate,'dd-Mon-yyyy HH24:mi');
return sReturn;
END FN_test;
Invoke from localDB:
select fn_test#RemoteDB.World(123) from Dual;
Thanks!
Any remote call opens transaction - even this executes just query. Oracle can't predict what exactly you do on remote side and tries to prevent uncommitted distributed transaction.
In example below I mere created local database link connecting to native host and just requested data from DUAL table using db link. Oracle has opened the local transaction in respond:
SQL> create database link locallink connect to scott identified by tiger
2 using '127.0.0.1:1521/test';
Database link created.
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
SQL> select * from dual#locallink;
D
-
X
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
17.13.10520
Autonomous transaction is useless because it opens and closes the transaction what is differ from the main one. So you need to commit changes in main transaction if you use remote calls.

Not able to insert the same record after connection interruption

I was inserting some records in the production table ,while doing that before commit ,I lost the production connection and none of the record got inserted.
Now when I am trying to insert the same record ,the sql plus is getting hanged and data is not getting saved.
But when I tried for other record which I was not inserted ,those records are getting inserted.
I have checked the table again ,for availability of data.Those previous data has not stored anywhere.
SQL plus is not generating any error also ,so that I can check the error and try to rectify.
Can anyone please help me to analyse and troubleshoot the problem.
while inserting in oracle the connection has lost now I am not able to add the same data
If your SQL/Plus session hangs, it's probably being blocked by your previous session. To find the offending session, you can use (requires DBA privileges):
select * from v$lock where block = 1
This should give you the session ID of the blocking session. Now you can run
select * from v$session
and check whether the session ID returned by the first query indeed belongs to your previous session. To kill the session, use the command
alter system kill session '<SID>,<serial#>'

Details of other databases accessing our Oracle database using DB links

Is there a way to find the details of the databases accessing our Oracle database using the DB links? Dba_db_links holds the information about the DB links that we have in our database to access other databases, but is there a similar kind of table from where we can find the DB links accessing our database or is that getting recorded some where?
Thanks in Advance.
I agree with Justin, that there's no way to determine an explicit list of all databases that have database links into a given database.
However, it is possible to monitor active database links. You can use the following query to see what sessions are via database links and from which databases:
-- who is querying via dblink?
-- Courtesy of Tom Kyte, via AskTom
-- this script can be used at both ends of the database link
-- to match up which session on the remote database started
-- the local transaction
-- the GTXID will match for those sessions
-- just run the script on both databases
Select /*+ ORDERED */
substr(s.ksusemnm,1,10)||'-'|| substr(s.ksusepid,1,10) "ORIGIN",
substr(g.K2GTITID_ORA,1,35) "GTXID",
substr(s.indx,1,4)||'.'|| substr(s.ksuseser,1,5) "LSESSION" ,
s2.username,
substr(
decode(bitand(ksuseidl,11),
1,'ACTIVE',
0, decode( bitand(ksuseflg,4096) , 0,'INACTIVE','CACHED'),
2,'SNIPED',
3,'SNIPED',
'KILLED'
),1,1
) "S",
substr(w.event,1,10) "WAITING"
from x$k2gte g, x$ktcxb t, x$ksuse s, v$session_wait w, v$session s2
where g.K2GTDXCB =t.ktcxbxba
and g.K2GTDSES=t.ktcxbses
and s.addr=g.K2GTDSES
and w.sid=s.indx
and s2.sid = w.sid;
Hope that helps.
When you create a database link in database A that points at database B, there is no notification sent to database B so there is no data dictionary table in B that will tell you that A has a link to it. As far as B is concerned, database A is simply another client that periodically opens a connection to the database.
Generally, when A wants to create a database link to B, a user will be created in B for this purpose (assuming the database link uses a fixed user rather than the current user) since you don't want the password for this account to expire regularly and you don't want the database link to be broken if a particular human leaves the company and has his or her accounts removed. You can audit connections on B, either for the particular accounts that have been created for database links or across all users, and then look through the audit logs to identify connections that are coming from servers that house other databases.
You might be looking out for this.
Step 1: Check the hash_value of the session in X database.
select sql_hash_value from v$session where sid=&sid;
Step 2: Check the full SQL of the session in X database where the SQL is fired.
select sql_fulltext from v$sql where hash_value=&hash_value;
Step 3: Make a note of all the DB links invloved in the SQL and identify the hosts for those DB links.
select * from dba_db_links where db_link like upper('&db_link');
Step 4: In each host (say only one remote host, pointing to database Y) and database X itself, fire the above query (Tom Kyte's) to gather the session details of sessions coming from remote DBs.
Step 5: In database X, check the SID of interest and its corresponding GTXID. Look for the same GTXID in the remote host Y.
Step 6: Get the session ID from the database Y for this GTXID and check the session waits or other details.

How can I close Oracle DbLinks in JDBC with XA datasources and transactions to avoid ORA-02020 errors?

I have a JDBC-based application which uses XA datasources and transactions which span multiple connections, connected to an Oracle database. The app sometimes needs to make some queries using join with a table from another (Oracle) server using a shared DbLink. The request works if I don't do it too often, but after 4 or 5 requests in rapid succession I get an error (ORA-02020 - too many links in use). I did some research, and the suggested remedy is to call "ALTER SESSION CLOSE DATABASE LINK ". If I call this request after the query that joins the DbLnk table, I get the error ORA-2080 (link is in use). If I call it before the query, I get ORA-2081 (link closed). Does this call do any good at all? The JDBC connection is closed long before the transaction commit (which is managed either by servlet or by EJB container, depending on the circumstances). I get the impression that when the connection closes, Oracle marks the link as closed, but it takes a minute or two for it to return to the pool of available links. I understand I could enlarge the pool of links (using the open_links property in the config file), but that won't guarantee that I won't have the same problem under a heavier load. Is there something I can do differently to get the dblinks to close more rapidly?
Any distributed SQL, even a select, will open a transaction that must be closed before you can close the database link. You need to either rollback or commit before you call ALTER SESSION CLOSE DATABASE LINK.
But it sounds like you've already got something else handling your transactions. If it's not possible to manually rollback or commit, you should try to increase the number of open links. The OPEN_LINKS parameter is the maximum number of links per session. The number of links you need isn't really dependent on the load, it should be based on the maximum number of distinct remote databases.
Edit:
The situation you describe in your comment shouldn't happen. I don't understand enough about your system to know what's really happening with the transactions. Anyway, if you can't figure out exactly what the system is doing maybe you can replace "alter session close database link" with a procedure like this:
create or replace procedure rollback_and_close_db_links authid current_user is
begin
rollback;
for links in (select db_link from v$dblink) loop
execute immediate 'alter session close database link '||links.db_link;
end loop;
end;
/
You'll probably need this grant:
grant select on v_$dblink to [relevant user];

Resources