I have an old appliation/executable that loads data to Oracle DB that we are reverse engineering. We'd like to see all the sql generated by the application without stepping through source code. The source code has many different versions and may not match the executable.
select v$sql.last_load_time, v$sql.sql_text
from v$sql
order by v$sql.last_load_time desc
First, you will need help from DBA to:
grant permission to select from table v$sql.
ALTER SYSTEM SET sql_trace = true SCOPE=MEMORY; when done
ALTER SYSTEM SET sql_trace = false SCOPE=MEMORY;
select sid, serial#, machine from sys.v_$session ; find the sid and serial# for your machine and input to the next command
execute sys.dbms_system.set_sql_trace_in_session(sid, serial#, true);
flush the cache by executing following commands:
alter system flush buffer_cache;
alter system flush shared_pool;
Related
I have a .net web service that makes some dynamically generated sql calls against ORACLE and they are performing bad in production. The DBAs keep asking for the sql ids to tune the query. They can use the OEM tool to find the slow performing query and get the sql id. But I was wondering if there is a way to know the sql id and log it so that I can retrieve it and give it to the DBAs for tuning.
Is this something that can be achieved in .net ?
Query the V$SQL dynamic view to get the SQL ID;
More on the V$SQL:
https://docs.oracle.com/cd/B19306_01/server.102/b14237/dynviews_2113.htm#REFRN30246
The following package dbms_application_info is very useful to instrument your queries.
Prior to running the processing logic from app layer, set the module/action, to identify your module.
DBMS_APPLICATION_INFO.set_module(module_name => 'add_order',
action_name => 'processing orders');
After that, set the client_info with a marker that indicates what processing is going on prior to running the sql.
Eg:
exec dbms_application_info.set_client_info('starting load from staging');
--Run the query
insert into dest_table select * from staging;
update dest_table set last_updated=sysdate;
exec dbms_application_info.set_client_info('updated the last_updated column');
delete from dest_table where order_value<0;
exec dbms_application_info.set_client_info('deleted -ve orders');
When this happens we can have a look at v$session/v$sql to see where the processing is currently taking place
SELECT sid,
serial#,
username,
osuser,
module,
action,
client_info
FROM v$session
WHERE module='add_order'
SELECT *
FROM v$sql
WHERE module='add_order'
have a look at the link
https://oracle-base.com/articles/8i/dbms_application_info
If the application can capture sufficient information to identify the session in v$session, you can query it from another session to grab the value of sql_id, or else query the v$sql_monitor view if you are licensed (requires Enterprise Edition and the Diagnostics and Tuning option). Use dbms_application_info to tag activity for better tracking.
Also you can configure database services if you haven't already, so that applications connect to a specific service rather than a generic one, and this will appear in v$session.service_name and be reported in OEM etc.
If it's practical to capture the session details from the same session immediately after the poorly-performing SQL statement completes (which it may not be, if the connection times out for example), you might try querying the prev_ details from v$session:
select s.prev_sql_id
, s.prev_child_number
, s.prev_exec_start
, s.prev_exec_id
, p.sql_text as prev_sql
, p.plan_hash_value as prev_plan
from v$session s
left join v$sql p on p.sql_id = s.prev_sql_id and p.child_number = s.prev_child_number
where s.audsid = sys_context('userenv', 'sessionid')
SQL Server 2017 Enterprise Query Store is showing no data at all but shows READ_ONLY as the actual mode
The one similar question in this forum has an answer that doesn't apply - none of the exclusions are present.
I ran:
GO
ALTER DATABASE [MyDB] SET QUERY_STORE (OPERATION_MODE = READ_ONLY, INTERVAL_LENGTH_MINUTES = 5, QUERY_CAPTURE_MODE = AUTO)
GO
I also ran all these, having referenced the link below, DB context is MyDB:
https://learn.microsoft.com/en-us/sql/relational-databases/performance/best-practice-with-the-query-store?view=sql-server-2017
ALTER DATABASE MyDB SET QUERY_STORE = ON;
SELECT actual_state_desc, desired_state_desc, current_storage_size_mb,
max_storage_size_mb, readonly_reason, interval_length_minutes,
stale_query_threshold_days, size_based_cleanup_mode_desc,
query_capture_mode_desc
FROM sys.database_query_store_options;
ALTER DATABASE MyDB SET QUERY_STORE CLEAR;
-- Run together...
ALTER DATABASE MyDB SET QUERY_STORE = OFF;
GO
EXEC sp_query_store_consistency_check
GO
ALTER DATABASE MyDB SET QUERY_STORE = ON;
GO
No issues found. The SELECT returns matching Actual and Desired states.
I am a sysadmin role member, who actually sets up all 30+ production servers, and this is the only miscreant.
The server is under heavy load and I need internal-eyes on it, in addition to Solarwinds DPA. I've also run sp_blitzquerystore but it returns an empty rowset from the top query, and just the two priority 255 rows from the 2nd.
What on earth did I do wrong? Any clues, anyone, please?
I know this is an old post but for those who come here looking for answers: I do see you ran the query with OPERATION_MODE = READ_ONLY. This would put it into a read-only mode - a mode in which it only reads what is stored in the query store without collecting any additional information. There will be no information shown if the query store has never been in READ_WRITE mode.
If it has been in READ_WRITE mode before and you are still not seeing anything, it is possible that the heavy load on the server is pushing query plans out of the cache.
I have an azure PaaS database and would like to clear cache to test some SP. So I found some scripts from the Internet:
-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;
-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;
-- list available plans
select * from sys.dm_exec_cached_plans;
select * from sys.dm_exec_procedure_stats
However, the amount of cache is always around 600-800, so somehow it is not dropping.
I didn't get any error (no permission denied etc), so how this command is not cleaning cache?
I haven't had time to debug through the code to be 100% sure, but based on my understanding of the system it is likely that merely bumping the database schema version (which happens on any alter database command) will invalidate the entries in the cache on next use. Since the procedure cache is instance wide, any attempt to clear the entries associated with the database would need to walk all entries one-by-one instead of merely freeing the whole cache.
So, you can think of this as invalidating the whole cache but lazily removing entries from the cache as they are recompiled or if the memory is reclaimed by other parts of the system through later actions.
Conor Cunningham
Architect, SQL
I contacted Microsoft support and understood it now.
Try to run the following T-SQL on AdventureWorks database.
-- create test procedure
create or alter procedure pTest1
as begin
select * from salesLT.product where ProductCategoryID =27
end
go
-- exec the procedure once.
exec pTest1
-- check for cached plan for this specific procedure - cached plan exists
select * from sys.dm_exec_cached_plans p
cross apply sys.dm_exec_sql_text(p.plan_handle) st
where p.objtype = 'proc' and st.objectid = OBJECT_ID('pTest1')
-- clear plan cache
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
-- check for cached plan for this specific procedure - not exists anymore
select * from sys.dm_exec_cached_plans p
cross apply sys.dm_exec_sql_text(p.plan_handle) st
where p.objtype = 'proc' and st.objectid = OBJECT_ID('pTest1')
-- cleanup
drop procedure pTest1
select 'cleanup complete'
with this sample, we can confirm that plan cache is cleared for the database, however, sys.dm_exec_cached_plans is server wide and give you results from other databases as well (internal system databases) that for them the cache was not cleared with the CLEAR PROCEDURE_CACHE command.
If I execute a simple select statement in pl/sql developer against a database table, I get a standard set of results back as I would expect.
Recently, I pasted a query from a stored procedure that happened to select from a view, and noticed that a transaction was seemingly left open. This was appraent by the rollback and commit options were available in PL/SQL developer.
A poll of other developers revealed that this seems to affect some but not others, which lead me to suspect PL/SQL Developer settings.
Why on earth would this be the case? The view itelf has a DBLink to another database, but I wouldn't expect this to have any effect.
Any thoughts?
Contrary to your expectation, it looks like the database link is the source of the open transaction. I've noticed behaviour like this before when running SELECT queries on remote tables in PL/SQL Developer.
To quote Tom Kyte (source):
distributed stuff starts a transaction "just in case".
EDIT: 'Any SQL statement starts a transaction in Oracle'? No, it does not, and here's a demonstration of it. This demonstration uses the data dictionary view V$TRANSACTION, which lists the active transactions. This is all running on my local Oracle XE database, which has no users other than me connected to it.
We'll use the following table during this demonstration. It contains only a single column:
SQL> desc test;
Name Null? Type
----------------------------------------- -------- ----------------------------
A NUMBER(38)
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
No active transactions at the moment. Let's run a SQL query against this table:
SQL> select * from test;
A
----------
2
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
Still no active transactions. Now let's do something that will start a transaction:
SQL> insert into test values (1);
1 row created.
SQL> select count(*) from v$transaction;
COUNT(1)
----------
1
As expected, we now have an active transaction.
SQL> commit;
Commit complete.
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
After committing the transaction, it's no longer active.
Now, let's create a database link. I'm using Oracle XE, and the following creates a database link from my Oracle XE instance back to itself:
SQL> create database link loopback_xe connect to user identified by password using 'XE';
Database link created.
Now let's see what happens when we select from the table over the database link:
SQL> select count(*) from v$transaction;
COUNT(1)
----------
0
SQL> select * from test#loopback_xe;
A
----------
2
1
SQL> select count(*) from v$transaction;
COUNT(1)
----------
1
As you can see, simply selecting from a remote table opens a transaction.
I'm not sure exactly what there is to commit or rollback here, but I have to admit to not knowing the ins and outs of distributed transactions, within which the answer probably lies.
Any SQL Statement starts a transaction in Oracle.
From the manual:
A transaction begins with the first executable SQL statement. A transaction ends when it is committed or rolled back, either explicitly with a COMMIT or ROLLBACK statement or implicitly when a DDL statement is issued. [...] An executable SQL statement is a SQL statement that generates calls to an instance, including DML and DDL statements
Most probably those who are not seing this are running in auto-commit mode where the transaction started by a statement is immediately committed after the statement has finished.
Others have claimed that a SELECT is not DML, but again the manual clearly states:
Data manipulation language (DML) statements query or manipulate data in existing schema objects. They enable you to:
* Retrieve or fetch data from one or more tables or views (SELECT)
* Add new rows of data into a table or view (INSERT)
[...]
You absolutely cannot open a transaction strictly with a normal query. You may open one across a database link. The guy who posted a link to the doctors either deliberately or utterly carelessly left out the 2nd sentence.
"A transaction in Oracle Database begins when the first executable SQL
statement is encountered. An executable SQL statement is a SQL
statement that generates calls to an instance, including DML and DDL
statements."
SELECT is neither a DML nor a DDL. It is also TRIVIAL to actually test this. I don't want to come off like a troll here, but its really annoying when people just throw out answers on a forum to try to get points and the answers are complete garbage.
Read the rest of the doc and TEST IT FIRST.
login to a session
run a select
see if you have an open transaction by joining v$Session (for your session) to v$transaction.
If a record comes back, you have a transaction. If not, you don't.
Note, according to the Oracle 11g Admin Guide, if you do a plain old SELECT across a database link you will start a transaction, which needs to be committed (or rolled back).
Select is a part of DML only but lock is not acquired, A row lock is fetched upon insert/update/delete/ select for update. -Ross is right.
https://docs.oracle.com/cd/E11882_01/server.112/e41084/ap_locks001.htm#SQLRF55502
ROW Lock Table lock
SELECT ... FROM table... ----- None
INSERT INTO table ... Yes SX
Same with update delete and select for update.
TLDR : On select from remote database you also create session and connection for remote DB. That session and connection persists as long as local user session. As you can guess this can lead to some problems with keeping up with session and connections.
SO ALWAYS DO A COMMIT :
SELECT * FROM emp#sales;
COMMIT;
I like a long read section :
This was bugging me also so much why there is an transaction on selects from db_links
and decided to finally end this so from oracle documentation :
Oracle® Database Administrator's Guide
11g Release 2 (11.2)
https://docs.oracle.com/html/E25494_01/ds_appdev002.htm
Controlling Connections Established by Database Links
When a global object name is referenced in a SQL statement or remote procedure call, database links establish a connection to a session in the remote database on behalf of the local user. The remote connection and session are only created if the connection has not already been established previously for the local user session.
The connections and sessions established to remote databases persist for the duration of the local user's session, unless the application or user explicitly terminates them. Note that when you issue a SELECT statement across a database link, a transaction lock is placed on the undo segments. To rerelease the segment, you must issue a COMMIT or ROLLBACK statement.
Terminating remote connections established using database links is useful for disconnecting high cost connections that are no longer required by the application. You can terminate a remote connection and session using the ALTER SESSION statement with the CLOSE DATABASE LINK clause. For example, assume you issue the following transactions:
SELECT * FROM emp#sales;
COMMIT;
The following statement terminates the session in the remote database pointed to by the sales database link:
ALTER SESSION CLOSE DATABASE LINK sales;
To close a database link connection in your user session, you must have the ALTER SESSION system privilege.
Note:
Before closing a database link, first close all cursors that use the link and then end your current transaction if it uses the link.
See Also:
Oracle Database SQL Language Reference for more information about the ALTER SESSION statement
I need to be able to drop a specific user (which may have active sessions) from the batch without any user interaction. I don't care about active sessions and want them to be dropped and rolled back. For Microsoft SQL i would do similar task with a single line:
osql -E -S localhost -b -Q "use master if ((select name from sysdatabases where name='%DB%') is not null) begin alter database [%DB%] set single_user with rollback immediate drop database [%DB%] end"
How do i do it for Oracle (10g XE on Windows)?
My current batch is:
sqlplus sys/*** as SYSDBA #delete1.sql >delete.log
sqlplus sys/***#XE as SYSDBA #delete2.sql >>delete.log
where delete1.sql:
startup force;
exit;
and delete2.sql:
drop user MYUSER cascade;
exit;
This is ugly as hell and takes too long comparing to the split second of MSSQL solution.
It should work if you use the following script (here named drop_user_with_active_sessions.sql):
set verify off
begin
for s in (
select
sid, serial#
from
v$session
where
username = '&1'
) loop
execute immediate
'alter system kill session ''' ||
s.sid || ',' ||
s.serial# || ''' immediate';
end loop;
execute immediate 'drop user &1';
end;
/
exit
And the use it with
sqlplus username/password#instance #c:\path\to\drop_user_with_active_session.sql MYUSER
you can do Oracle SQL via the command prompt and then do your cascade drop user.
I would recommend creating a sql script and executing it from the command line.
then you can wrap up command line text in your cmd/batch file.
but if you would like Oracle to handle the entire process I would recommend looking into the job/schedule environment
In addition to "alter system kill session" mentioned above I've also needed to preface the kill session with something like:
execute immediate 'ALTER SYSTEM DISCONNECT SESSION ''' ||
to_char(s.sid) || ', ' || to_char(s.serial#) || ''' IMMEDIATE'
It's a very, very bad idea to take a construct from one Database platform and assume I can run the exact same thing on a different platform. For example. Oracle has Create OR REPLACE procedure. MSSS isn't quite so simple. MSSS you can make a "temp" table with #name, in Oracle we use DDL. While dropping a user to recreate a fresh environment may have been the simplest approach on MSSS, perhaps there's a more Oracle-centric way to accomplish the same thing. It's a very good idea to ask for help on how to accomplish a task instead of why your way isn't working.
First, does the app being tested do DDL? to the tables and other objects?
If it only changes data, they way Oracle prefers apps to work, then why do you have to recreate all the objects. You just need to get the data back to the starting point.
Have you looked into Flashback Database? You should be able to create a restore point... do whatever you want and then flashback the database to that point in time.