I'm looking for a way to find out if there are uncommited INSERT, UPDATE or DELETE statements in the current session. One way would be to check v$lock with the current sid, but that requires read access to v$lock, which is a problem if the DBA doesn't want to grant it. Any other ways (other than keeping track of all database commands issued by the application)?
you can check if your session has a row in V$TRANSACTION (obviously that requires read privilege on this view):
SQL> SELECT COUNT(*)
FROM v$transaction t, v$session s, v$mystat m
WHERE t.ses_addr = s.saddr
AND s.sid = m.sid
AND ROWNUM = 1;
COUNT(*)
----------
0
SQL> insert into a values (1);
1 row inserted
SQL> SELECT COUNT(*)
FROM v$transaction t, v$session s, v$mystat m
WHERE t.ses_addr = s.saddr
AND s.sid = m.sid
AND ROWNUM = 1;
COUNT(*)
----------
1
SQL> commit;
Commit complete
SQL> SELECT COUNT(*)
FROM v$transaction t, v$session s, v$mystat m
WHERE t.ses_addr = s.saddr
AND s.sid = m.sid
AND ROWNUM = 1;
COUNT(*)
----------
0
This is the query I normally use,
select s.sid
,s.serial#
,s.username
,s.machine
,s.status
,s.lockwait
,t.used_ublk
,t.used_urec
,t.start_time
from v$transaction t
inner join v$session s on t.addr = s.taddr;
SELECT * FROM V$TRANSACTION
WHERE STATUS='ACTIVE';
See:
http://forums.oracle.com/forums/thread.jspa?threadID=691061
Use the query below to find out pending transaction.
If it returns a value, it means there is a pending transaction.
Here is the query:
select dbms_transaction.step_id from dual;
References:
http://www.acehints.com/2011/07/how-to-check-pending-transaction-in.html
http://www.acehints.com/p/site-map.html
Also see...
How can I tell if I have uncommitted work in an Oracle transaction?
Matthew Watson can be modified to be used in RAC
select t.inst_id
,s.sid
,s.serial#
,s.username
,s.machine
,s.status
,s.lockwait
,t.used_ublk
,t.used_urec
,t.start_time
from gv$transaction t
inner join gv$session s on t.addr = s.taddr;
The easiest and most reliable solution is to try and start a transaction and see it if succeeds. If some code already started a transaction but has not yet issued any DML, then the V$TRANSACTION view won't show anything.
In this example below, I handle the exception to raise a user-defined application error. To defer to an existing exception handler, just do a SET TRANSACTION and then immediately COMMIT to undo it.
DECLARE
transaction_in_progress EXCEPTION;
PRAGMA EXCEPTION_INIT(transaction_in_progress, -1453);
BEGIN
SET TRANSACTION NAME 'CHECK_FOR_TRANSACTION_ALREADY_SET';
COMMIT; -- end transaction
EXCEPTION
WHEN transaction_in_progress THEN
RAISE_APPLICATION_ERROR(-20000,'Transaction is already in progress');
END;
/
Related
I develop procedure in Oracle
I need write something like this:
--
open curr1 for
select *
from table1
where key_field in (select key_field from tbl_keys where type = 1);
--
open curr2 for
select *
from table2
where key_field in (select key_field from tbl_keys where type = 1);
--
open curr3 for
select *
from table3
where key_field in (select key_field from tbl_keys where type = 1);
--
Is there a better way to do this?
Any optimization for inner select?
Thanks!
I think Oracle will try to cache the results of your tbl_keys subquery, so if it returns a small number of rows, your queries are probably fine the way they are.
I don't know if it's better, but if you're having performance problems an alternate method you could try is to join the tables, e.g.
open curr1 for
select t.*
from table1 t
join tbl_keys k
on k.key_field = t.key_field
and k.type = 1;
This might improve performance if your tbl_keys table is very large.
Personally, I prefer using implicit cursor loops whenever possible - they're simple and can be very fast - but I don't know if it would work for your procedure, since you didn't show the rest of it.
for r in (select t.*
from table1 t
join tbl_keys k
on k.key_field = t.key_field
and k.type = 1)
loop
-- output the row somehow
end loop;
for r in (select t.*
from table2 t
join tbl_keys k
on k.key_field = t.key_field
and k.type = 1)
loop
-- output the row somehow
end loop;
...etc
I'm currently migrating data from legacy system to the current system.
I have this INSERT statement inside a stored procedure.
INSERT INTO TABLE_1
(PRIMARY_ID, SEQUENCE_ID, DESCR)
SELECT LEGACY_ID PRIMARY_ID
, (SELECT COUNT(*) + 1
FROM TABLE_1 T1
WHERE T1.PRIMARY_ID = L1.LEGACY_ID) SEQUENCE_ID
, L1.DESCR
FROM LEGACY_TABLE L1;
However, whenever I have multiple values of LEGACY_ID from LEGACY_TABLE, the query for the SEQUENCE_ID doesn't increment.
Why is this so? I can't seem to find any documentation on how the INSERT INTO SELECT statement works behind the scenes. I am guessing that it selects all the values from the table you are selecting and then inserts them simultaneously after, that's why it doesn't increment the COUNT(*) value?
What other workarounds can I do? I cannot create a SEQUENCE because the SEQUENCE_ID must be based on the number of PRIMARY_ID that are present. They are both primary ids.
Thanks in advance.
Yes, The SELECT will be executed FIRST and only then the INSERT happens.
A Simple PL/SQL block below, will be a simpler approach, though not efficient.
DECLARE
V_SEQUENCE_ID NUMBER;
V_COMMIT_LIMIT:= 20000;
V_ITEM_COUNT := 0;
BEGIN
FOR REC IN (SELECT LEGACY_ID,DESCR FROM LEGACY_TABLE)
LOOP
V_SEQUENCE_ID:= 0;
SELECT COUNT(*)+1 INTO V_SEQUENCE_ID FROM TABLE_1 T1
WHERE T1.PRIMARY_ID = REC.LEGACY_ID
INSERT INTO TABLE_1
(PRIMARY_ID, SEQUENCE_ID, DESCR)
VALUES
(REC.LEGACY_ID,V_SEQUENCE_ID,REC.DESCR);
V_ITEM_COUNT := V_ITEM_COUNT + 1;
IF(V_ITEM_COUNT >= V_COMMIT_LIMIT)
THEN
COMMIT;
V_ITEM_COUNT := 0;
END IF;
END LOOP;
COMMIT;
END;
/
EDIT: Using CTE:
WITH TABLE_1_PRIM_CT(PRIMARY_ID, SEQUENCE_ID) AS
(
SELECT L1.LEGACY_ID,COUNT(*)
FROM LEGACY_TABLE L1
LEFT OUTER JOIN TABLE_1 T1
ON(L1.LEGACY_ID = T1.PRIMARY_ID)
GROUP BY L1.LEGACY_ID
)
INSERT INTO TABLE_1
(SELECT L1.LEGACY_ID,
CTE.SEQUENCE_ID+ (ROW_NUMBER() OVER (PARTITION BY L1.LEGACY_ID ORDER BY null)),
L1.DESCR
FROM TABLE_1_PRIM_CT CTE, LEGACY_TABLE L1
WHERE L1.LEGACY_ID = CTE.PRIMARY_ID);
PS: With your Millions of Rows, this is going to create a temp table
of same size, during execution. Do Explain Plan before actual execution.
Is there any way to uniquely identify current session in GV$SESSION view in Oracle?
I've faced with the problem that the following query may return more than one row in case of Oracle RAC configuration:
SELECT SID, SERIAL#
FROM GV$SESSION
WHERE AUDSID = Sys_Context('USERENV', 'SESSIONID')
AND SID = Sys_Context('USERENV', 'SID');
Using V$MYSTAT is not an option either, because V$MYSTAT may not be accessible for the current session (for example when statistic is disabled).
Try this:
SELECT SID, SERIAL#
FROM V$SESSION
WHERE AUDSID = Sys_Context('USERENV', 'SESSIONID');
Since you're interested in current session, the current session must be on the local instance (by definition), so use V$SESSION instead of GV$SESSION. Also, all you need is AUDSID to uniquely identify your session.
If you've got some reason you really need to use GV$SESSION (can't imagine why that would be), you could do this instead:
SELECT SID, SERIAL#
FROM GV$SESSION
WHERE AUDSID = Sys_Context('USERENV', 'SESSIONID')
AND INST_ID = USERENV('Instance');
Also, an alternate way to get the SID of the current session is:
select sid from v$mystat where rownum=1;
Hope that helps.
Joining gv$session and v$mystat :)
SELECT SID, SERIAL#,inst_id
FROM GV$SESSION
WHERE sid=(select sid from v$mystat where rownum=1);
Use V$SESSION instead of GV$SESSION
SELECT SID, SERIAL#
FROM V$SESSION
WHERE SID = Sys_Context('USERENV', 'SID');
Try this (will need access to v$session and v$sql views) -
select /*My Sess*/ 'My Sess Text = hello world # '||systimestamp SID_SR_TXT from dual
union
select 'SID = '||sid||' Serial# = '||serial# SID_SR_TXT from v$session where sql_id in
(select sql_id from v$sql where sql_text like '% My Sess %');
which column i need to use to join V$session and V$sqlarea?
My main aim is to find top 5 queries with most disk_reads and generate a report containing relevant information.
Thanks
Try below one, I think it satisfy your requirement.
Find top 5 queries with most disk_reads.
SELECT SESION.SID,
SESION.USERNAME,
OPTIMIZER_MODE,
HASH_VALUE,
ADDRESS,
CPU_TIME,
ELAPSED_TIME,
DISK_READS,
DIRECT_WRITES,
SQL_TEXT
FROM V$SQLAREA SQLAREA, V$SESSION SESION
WHERE SESION.SQL_HASH_VALUE = SQLAREA.HASH_VALUE
AND SESION.SQL_ADDRESS = SQLAREA.ADDRESS
AND SESION.USERNAME IS NOT NULL
AND ROWNUM < 6
ORDER BY DISK_READS DESC,ELAPSED_TIME DESC;
This SQL does the join:
select s.sid, s.serial#, a.sql_text
from v$session s
join v$sqlarea a on a.hash_value = s.sql_hash_value;
What is the query to find the number of current open cursors in an Oracle Instance?
Also, what is the accuracy/update frequency of this data?
I am using Oracle 10gR2
Total cursors open, by session:
select a.value, s.username, s.sid, s.serial#
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and b.name = 'opened cursors current';
Source: http://www.orafaq.com/node/758
As far as I know queries on v$ views are based on pseudo-tables ("x$" tables) that point directly to the relevant portions of the SGA, so you can't get more accurate than that; however this also means that it is point-in-time (i.e. dirty read).
select sql_text, count(*) as "OPEN CURSORS", user_name from v$open_cursor
group by sql_text, user_name order by count(*) desc;
appears to work for me.
Here's how to find open cursors that have been parsed. You need to be logged in as a user with access to v$open_cursor and v$session.
COLUMN USER_NAME FORMAT A15
SELECT s.machine, oc.user_name, oc.sql_text, count(1)
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC
;
If gives you part of the SQL text so it can be useful for identifying leaky applications. If a cursor has not been parsed, then it does not appear here. Note that Oralce will sometimes keep things open longer than you do.
1)your id should have sys dba access
2)
select sum(a.value) total_cur, avg(a.value) avg_cur, max(a.value) max_cur,
s.username, s.machine
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and b.name = 'opened cursors current'
group by s.username, s.machine
order by 1 desc;
Oracle has a page for this issue with SQL and trouble shooting suggestions.
"Troubleshooting Open Cursor Issues"
http://docs.oracle.com/cd/E40329_01/admin.1112/e27149/cursor.htm#OMADM5352
I use something like this:
select
user_name,
count(*) as "OPEN CURSORS"
from
v$open_cursor
group by
user_name;
This could work:
SELECT sql_text "SQL Query",
Count(*) AS "Open Cursors"
FROM v$open_cursor
GROUP BY sql_text
HAVING Count(*) > 2
ORDER BY Count(*) DESC;
I would use this quick SQL to compare the highest current use compared to the max allowed. This will allow you to immediately see if any process has a dangerously high use of cursors.
SELECT MAX (a.VALUE) AS highest_open_cur, p.VALUE AS max_open_cur
FROM v$sesstat a, v$statname b, v$parameter p
WHERE a.statistic# = b.statistic#
AND b.name = 'opened cursors current'
AND p.name = 'open_cursors'
GROUP BY p.VALUE;
As is probably clear from the above SQL, the OPEN_CURSORS value is an Oracle parameter and can be found at runtime like this.
SELECT * FROM v$parameter WHERE NAME = 'open_cursors';
You may need to be sysdba or equivalent to query the above tables.