ORACLE Join V$SQLAREA V$SESSION - oracle

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;

Related

Oracle SQL -- Finding count of rows that match date maximum in table

I am trying to use a query to return the count from rows such that the date of the rows matches the maximum date for that column in the table.
Oracle SQL: version 11.2:
The following syntax would seem to be correct (to me), and it compiles and runs. However, instead of returning JUST the count for the maximum, it returns several counts more or less like the "HAIVNG" clause wasn't there.
Select ourDate, Count(1) as OUR_COUNT
from schema1.table1
group by ourDate
HAVING ourDate = max(ourDate) ;
How can this be fixed, please?
You can use:
SELECT MAX(ourDate) AS ourDate,
COUNT(*) KEEP (DENSE_RANK LAST ORDER BY ourDate) AS ourCount
FROM schema1.table1
or:
SELECT ourDate,
COUNT(*) AS our_count
FROM (
SELECT ourDate,
RANK() OVER (ORDER BY ourDate DESC) AS rnk
FROM schema1.table1
)
WHERE rnk = 1
GROUP BY ourDate
Which, for the sample data:
CREATE TABLE table1 (ourDate) AS
SELECT SYSDATE FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT SYSDATE - 1 FROM DUAL;
Both output:
OURDATE
OUR_COUNT
2022-06-28 13:35:01
5
db<>fiddle here
I don't know if I understand what you want. Try this:
Select x.ourDate, Count(1) as OUR_COUNT
from schema1.table1 x
where x.ourDate = (select max(y.ourDate) from schema1.table1 y)
group by x.ourDate
One option is to use a subquery which fetches maximum date:
select ourdate, count(*)
from table1
where ourdate = (select max(ourdate)
from table1)
group by ourdate;
Or, a more modern approach (if your database version supports it; 11g doesn't, though):
select ourdate, count(*)
from table1
group by ourdate
order by ourdate desc
fetch first 1 rows only;
You can use this SQL query:
select MAX(ourDate),COUNT(1) as OUR_COUNT
from schema1.table1
where ourDate = (select MAX(ourDate) from schema1.table1)
group by ourDate;

Report Job difference in HR schema

I'm new to Oracle and try to practice with HR schema. For example I want to report of those whose job is different from the previous job.
Employee name in employees table and job history in job_history table.
I think the following query will help. (I am considering that current JOB_ID is present in the EMPLOYEES table and you want to compare it with the latest previous JOB_ID from JOB_HISTORY table for the employee)
SELECT E.*, JH.LATEST_PREV_JOB_ID
FROM EMPLOYEES E
JOIN (SELECT FIRST_VALUE(JH.JOB_ID) OVER (PARTITION BY JH.EMPLOYEE_ID
ORDER BY JH.START_DATE DESC NULLS LAST) AS LATEST_PREV_JOB_ID,
JH.EMPLOYEE_ID
FROM JOB_HISTORY JH) JH
ON E.EMPLOYEE_ID = JH.EMPLOYEE_ID
WHERE E.JOB_ID <> JH.LATEST_PREV_JOB_ID
----- Update
You want the query without partition by clause (i.e. without WINDOWS function), We can use the NOT EXISTS as follows:
SELECT E.*, JH.LATEST_PREV_JOB_ID
FROM EMPLOYEES E
JOIN (SELECT JH.JOB_ID AS LATEST_PREV_JOB_ID,
JH.EMPLOYEE_ID
FROM JOB_HISTORY JH
WHERE NOT EXISTS (SELECT 1 FROM JOB_HISTORY JHIN
WHERE JHIN.EMPLOYEE_ID = JH.EMPLOYEE_ID
AND JHIN.START_DATE > JH.START_DATE)) JH
ON E.EMPLOYEE_ID = JH.EMPLOYEE_ID
WHERE E.JOB_ID <> JH.LATEST_PREV_JOB_ID
If I understood right your question, then the answer maybe something like this:
select
e.first_name,
e.last_name,
e.job_id as prev_job,
jh.job_id as last_lob
from
employees e,
job_history jh,
(select
employee_id,
max(end_date) as max_end_date
from
job_history
group by
employee_id
) t
where
(jh.employee_id = e.employee_id) and
(jh.job_id <> e.job_id) and
(jh.end_date = t.max_end_date) and
(t.employee_id = jh.employee_id)

How to find parameters in Oracle query received from v$sql?

I use query:
select LAST_LOAD_TIME, ELAPSED_TIME, MODULE, SQL_TEXT elasped from v$sql
WHERE MODULE='JDBC Thin Client'
ORDER BY LAST_LOAD_TIME DESC
elasped:
delete from tableA where fk in (select pk from tableB where tableB.fk=:1
and tableB.date between :2 and :3)
Is it possible find these parameters 1, 2 and 3?
Something like this:
select s.sql_id,
bc.position,
bc.value_string,
s.last_load_time,
bc.last_captured
from v$sql s
left join v$sql_bind_capture bc
on bc.sql_id = s.sql_id
and bc.child_number = s.child_number
where s.sql_text like 'delete from tableA where fk%' -- or any other method to identify the SQL statement
order by s.sql_id, bc.position;

Oracle Optimizer Unexpected Results

I have a co worker who wrote the following query. The first one works and the second one does not. Also if you remove the aggregate function from the subquery, it works. The oracle optimizer is doing something weird. Any thoughts? Running in SQL Developer 3.1 against 11.1.0.6.0 64 bit.
This works:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.counter is null
This doesn’t:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.fd_customer_key is null
Actually yes, both of the queries you provided are supposed to wrok the same way, but if i understand your need well, you are trying to select the fd_customer_key which has no Order?
I suggest the following query for your need, its more simple and less consuming :
SELECT a.fd_customer_key
FROM FETCH_CUSTOMER a
WHERE NOT EXISTS (SELECT 1
FROM fetch_customer_order b
WHERE a.fd_customer_key = b.fd_customer_key)
It seems like you are trying to make an anti-join (find the rows from FETCH_CUSTOMER that have no corresponding rows in FETCH_CUSTOMER_ORDER).
With Oracle you do not have to use this clever OUTER JOIN trick to write an anti-join, you could use a NOT IN or NOT EXISTS operator and let the optimizer find the best plan. This will be just as efficient and easier to read.
Anyway, I can't reproduce your findings, here's my setup:
CREATE TABLE a (ID NUMBER PRIMARY KEY);
CREATE TABLE b (a_id NUMBER NOT NULL, DATA VARCHAR2(30));
INSERT INTO a (SELECT object_id FROM all_objects);
INSERT INTO b (SELECT object_id, object_name
FROM all_objects WHERE object_type = 'VIEW');
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.cnt IS NULL;
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.a_id IS NULL;
You will find that both queries return rows. What is your DB version?

How to find Current open Cursors in Oracle

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.

Resources