Oracle - How to execute this script in parallel - oracle

I have a script to kill all sessions in Oracle:
declare
begin
for rec in (
SELECT username,machine,sid,serial#,inst_id from gv$session where type <> 'BACKGROUND'
and sid <> (select sys_context('userenv','sid') from dual) and status <> 'KILLED'
and username not in ('SYSRAC','SYS')
)
loop
execute immediate 'alter system disconnect session '''|| rec.sid|| ',' || rec.serial# || ',#' ||rec.inst_id||''' immediate';
end loop;
end;
/
Once a month I need kill all session before execute several scripts to add/remove/modify columns, grants and revokes, create new objects, drop objects etc..
This database usually has more than 2000 connections and when I execute this script it takes from 15 to 20 minutes to kill all sessions. How can I execute this script in parallel and kill all sessions faster?

A few things to absorb there ...
2000 connections sounds like overkill, especially if you're killing all of them which suggests they all belong to the same app. I'd be checking your connection pooling stats to ensure this isn't too many.
It might be worth checking out edition based redefinition to allow deployment without any downtime
If you're killing everything anyway, just do shutdown abort/startup and you're done
If you really want to kill those sessions, then you can use DBMS_PARALLEL_EXECUTE to get the job scheduler to run these concurrently.
But step back and take a look at the whole picture here, because generally, we don't kill all sessions to deploy code.

Related

What is the way to kill an executing procedure?

I am using Oracle sql developer. I have a procedure involving MINUS statement between two tables (table 1 and table 2). The table 1 has more than a million rows data. In this situation, when I am trying to execute it, it returns nothing but is in executing stage.
Meanwhile, I need to truncate this table data. But, when doing this, I got a resource busy error. How to terminate the executing stored procedure and how to do truncate operation meanwhile?
You do not kill a procedure, you kill a session.
Before killing the session, you might want to know that readers do not block writers and vice-versa. So, if you want to select/project the rows from the table being modified, you could always do it.
Identify the session:
SELECT s.sid,
s.serial#,
p.spid,
s.username,
s.program
FROM v$session s
JOIN v$process p ON p.addr = s.paddr
WHERE s.type != 'BACKGROUND';
Kill the session:
ALTER SYSTEM KILL SESSION 'sid,serial#';
The KILL SESSION command doesn't actually kill the session. It merely asks the session to kill itself. In some situations, like waiting for a reply from a remote database or rolling back transactions, the session will not kill itself immediately and will wait for the current operation to complete. In these cases the session will have a status of "marked for kill". It will then be killed as soon as possible.
In addition to the syntax described above, you can add the IMMEDIATE clause.
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
This does not affect the work performed by the command, but it returns control back to the current session immediately, rather than waiting for confirmation of the kill.
Read this article for more details.

Oracle: automate dropping and recreating connected user

I am trying to DROP a connected user with Oracle. This question has been asked well over 700 million times, thanks to Oracle being a great software product. All answers I find, however, require user input and can not be automated as posted. The typical answer is well stated here: https://stackoverflow.com/a/15665694/177293
I want to do this in a script without a human having to intervene. So, I'm trying like this:
BEGIN
FOR i IN (
SELECT sid, serial# from v$session where username = 'MYUSER'
) LOOP
EXECUTE IMMEDIATE 'alter system kill session ''' || i.sid || ',' || i.serial# || ''';';
END LOOP;
END;
Which, hilariously, in sqlplus results in:
BEGIN
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 5
Trying a slightly different tactic:
BEGIN
FOR i IN (
SELECT
'alter system kill session ''' || sid || ',' || serial# || ''';'
from v$session where username = 'MYUSER'
) LOOP
EXECUTE IMMEDIATE ''|| i ||'';
END LOOP;
END;
results in:
EXECUTE IMMEDIATE ''|| i ||'';
*
ERROR at line 7:
ORA-06550: line 7, column 21:
PLS-00306: wrong number or types of arguments in call to '||'
ORA-06550: line 7, column 3:
PL/SQL: Statement ignored
I'm hoping to have a finished script that looks something like this:
#!/bin/sh
sqlplus system/manager <<EOT
BEGIN
FOR i IN (
SELECT sid, serial# FROM v$session WHERE username = 'MYUSER'
) LOOP
EXECUTE IMMEDIATE 'alter system kill session ''' || i.sid || ',' || i.serial# || ''';';
END LOOP;
END;
DROP USER MYUSER CASCADE;
DROP TABLESPACE MYUSER INCLUDING CONTENTS AND DATAFILES;
CREATE USER MYUSER IDENTIFIED BY password;
ALTER USER MYUSER IDENTIFIED BY password;
GRANT connect, resource TO MYUSER;
exit;
EOT
What is wrong with the above?
The main problem with the above scripts is that ; should not be in dynamic SQL.
But don't let that fool you, this is still an incredibly difficult problem. Unfortunately, it is rare for Oracle systems to frequently drop and re-create users. This means you will run into lots of weird bugs.
I've built scripts to do this, but unfortunately cannot share them here. Here are some of the fun things you have to look forward to:
Killing connected sessions.
Killing other sessions that are blocking objects owned by your session.
Truncating temporary tables because they have weird locking rules. And killing sessions using them, see HOW TO DIAGNOSE AN ORA-14452 DURING DROP OF TEMPORARY TABLE (Doc ID 800506.1).
Using INST_ID in the KILL syntax, for RAC.
Looping through the whole process a few times, in case an application is spawning new sessions that lock objects.
If you're using object-relational code, execute dbms_session.reset_package. Amazingly, some objects can persist even after dropping and recreating their owners.
Expect to write about a hundred lines of code, if it's a complicated application. Expect to spend a few weeks of testing to shake out some weird bugs. Expect it to still fail occasionally.
Yes, this is ridiculous. Oracle spends a lot of effort on ways to quickly create new databases; transportable tablespaces, pluggable databases, virtualization, etc. You'd think there would be a good way to reliably drop and recreate a user!

How to see and kill a list of sessions being made to an ORACLE schema?

I am attempting to diagnose an issue and for that need to see the list of connections being made to a specific Oracle Schema.
Assuming that I have DBA privileges, what are the queries that I should run to :
List the sessions (active and otherwise) to an Oracle schema and,
Kill these sessions
Thank you!
Here are the queries you will need to execute:
-- 1. Check connected sessions
select sid, serial#, username, machine,
to_char(logon_time+5/24,'ddMon hh24:mi') login,
SQL_HASH_VALUE, PREV_HASH_VALUE,
status
from v$session
where
lower(username) like '%SCHEMA_NAME%'
--and lower(status) not like '%killed%'
--and machine like '%SOURCE_MACHINE_NAME%'
order by logon_time;
-- 2. Same as above, but just show the count of sessions
select count(1)
from v$session
where lower(username) like lower('%SCHEMA_NAME%')
--and lower(status) not like '%inactive%'
order by logon_time;
-- 3. Kill connected sessions
ALTER SYSTEM ENABLE RESTRICTED SESSION;
begin
for x in (
select Sid, Serial#, machine, program
from v$session
where lower(username) like '%SCHEMA_NAME%'
) loop
execute immediate 'Alter System Kill Session '''|| x.Sid
|| ',' || x.Serial# || ''' IMMEDIATE';
end loop;
end;
ALTER SYSTEM DISABLE RESTRICTED SESSION;
-- May have to wait for a bit for the killed sessions to be cleaned up
I have been using the above on an Oracle 11g database so would expect them to work for you too.
Note that I have included some commented out where clauses in the first two queries which would allow you to refine the search criteria.
Hope this is what you were looking for.

Oracle procedure to kill jobs that do not complete in given time

I have created an oracle procedure to reschedule job that do not complete in a given amount of time:
create or replace procedure kill_stuck_jobs
as
begin
for x in (
select j.sid,
s.spid,
s.serial#,
j.log_user,
j.job,
j.broken,
j.failures,
j.last_date,
j.this_date,
j.next_date,
j.next_date - j.last_date interval,
j.what
from
(select
djr.SID,
dj.LOG_USER,
dj.JOB,
dj.BROKEN,
dj.FAILURES,
dj.LAST_DATE,
dj.LAST_SEC,
dj.THIS_DATE, dj.THIS_SEC,
dj.NEXT_DATE, dj.NEXT_SEC, dj.INTERVAL, dj.WHAT
from dba_jobs dj, dba_jobs_running djr
where dj.job = djr.job ) j,
(select p.spid, s.sid, s.serial#
from v$process p, v$session s
where p.addr = s.paddr ) s
where j.sid = s.sid and
j.next_date+15/1440 < sysdate
) loop
EXEC DBMS_JOB.BROKEN(x.job,TRUE);
execute immediate 'alter system disconnect session '''|| x.sid|| ',' || x.serial# || ''' immediate';
EXEC DBMS_JOB.BROKEN(x.job,FALSE);
dbms_output.put_line( 'Alter session done' );
end loop;
end;
But this procedure compiles with error:
PLS-00103: Encountered the symbol "DBMS_JOB" when expecting one of the following:
:= . ( # % ;
The symbol ":=" was substituted for "DBMS_JOB" to continue.
Here came the discussion on dbms_job and dbms_scheduler_job. Actually the problem here is I created materialized view using linked db but sometime the query is stuck for whole day in session with SQL*Net more data from dblink . I used the above procedure to kill jobs that are created while creating materialized view and I am killing the session using :
create or replace procedure kill_stuck_refresh as
begin
for x in (
select username, osuser, sid, serial#, seconds_in_wait,
event, state, wait_class
from v$session
where username is not null
and seconds_in_wait > 600
and event = 'SQL*Net more data from dblink'
) loop
execute immediate 'alter system disconnect session '''|| x.sid
|| ',' || x.serial# || ''' immediate';
dbms_output.put_line( 'Alter session done' );
end loop;
end; -- end of kill_stuck_refresh;
Your error stack all derives from the fact that your cursor is invalid. The cause is the ORA-00942. This can mean the table name is spelled wrong, but as you're using the data dictionary it usually points to a permissions problem, that is, the tables (or views in this case) do not exist in your scope.
Which brings us to your comment:
"I can run the select query independently I think that mean I have
those priviledge. "
This suggests to me that your permissions have been granted to a role you have rights on. We can use permissions granted through roles in SQL but cannot use them to build permanent objects such as views or stored procedures. For this to work you need to have permissions on those views granted directly to your user. There is no workaround, this is the way the Oracle security model works.
Incidentally, you should investigate why these jobs are taking too long. I'm assuming this is a persistent problem (otherwise why are you building a stored proc to kill these jobs?). Killing jobs is a blunt instrument which wastes resources and obliterates helpful evidence. A better idea would be to find out the underlying cause of the poor performance and fix it. Perhaps there's a problem with blocking sessions and you need a locking strategy. Maybe you've got soem poorly tuned SQL. Some other job may be running at the same time and sucks up all the resources, in which case you need a decent scheduler. Or possibly you've just got more data now - the price of success - and you need to give the jobs more time to complete.
You do not need EXEC in this context (in a stored procedure/function). It's only needed when you want to call a stored procedure from SQL (from SQL*Plus). Just call dbms_job.broken() directly:
...
DBMS_JOB.BROKEN(x.job,TRUE);
execute immediate 'alter system disconnect session '''|| x.sid|| ',' || x.serial# || ''' immediate';
DBMS_JOB.BROKEN(x.job,FALSE);
dbms_output.put_line( 'Alter session done' );
...
As #David Aldridge mentioned, DBMS_Scheduler is largely meant to replace DBMS_Job (starting with 10g, actually). What he didn't mention is why this would help you.
DBMS_Scheduler provides a lot more control over it's jobs, including better logging. However, most significantly for you, DBMS_Scheduler adds a max_run_duration parameter to the job. If a job's run-time surpasses that duration, the job is automatically ended (and probably in a more graceful fashion than killing the session). Then, as long as the max_failures parameter isn't set, the job will be attempted again at it's next scheduled time.
If you can migrate your current jobs to DBMS_Scheduler, you can save yourself the trouble of writing code to provide functionality that already exists.
If you are using Oracle 11g then you ought to be using DBMS_Scheduler, not DBMS_Job. Look first at migrating to the new package, and rethink your requirement in that context.

Dropping a connected user from an Oracle 10g database schema

Is there a better way to forcefully disconnect all users from an Oracle 10g database schema than restarting the Oracle database services?
We have several developers using SQL Developer connecting to the same schema on a single Oracle 10g server. The problem is that when we want to drop the schema to rebuild it, inevitably someone is still connected and we cannot drop the database schema or the user while someone is still connected.
By the same token, we do not want to drop all connections to other schemas because other people may still be connected and testing with those schemas.
Anyone know of a quick way to resolve this?
To find the sessions, as a DBA use
select sid,serial# from v$session where username = '<your_schema>'
If you want to be sure only to get the sessions that use SQL Developer, you can add and program = 'SQL Developer'. If you only want to kill sessions belonging to a specific developer, you can add a restriction on os_user
Then kill them with
alter system kill session '<sid>,<serial#>'
(e.g. alter system kill session '39,1232')
A query that produces ready-built kill-statements could be
select 'alter system kill session ''' || sid || ',' || serial# || ''';' from v$session where username = '<your_schema>'
This will return one kill statement per session for that user - something like:
alter system kill session '375,64855';
alter system kill session '346,53146';
Find existing sessions to DB using this query:
SELECT s.inst_id,
s.sid,
s.serial#,
p.spid,
s.username,
s.program
FROM gv$session s
JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id
WHERE s.type != 'BACKGROUND';
you'll see something like below.
Then, run below query with values extracted from above results.
ALTER SYSTEM KILL SESSION '<put above s.sid here>,<put above s.serial# here>';
Ex:
ALTER SYSTEM KILL SESSION '93,943';
my proposal is this simple anonymous block:
DECLARE
lc_username VARCHAR2 (32) := 'user-name-to-kill-here';
BEGIN
FOR ln_cur IN (SELECT sid, serial# FROM v$session WHERE username = lc_username)
LOOP
EXECUTE IMMEDIATE ('ALTER SYSTEM KILL SESSION ''' || ln_cur.sid || ',' || ln_cur.serial# || ''' IMMEDIATE');
END LOOP;
END;
/
Make sure that you alter the system and enable restricted session before you kill them or they will quickly log back into the database before you get your work completed.
Just my two cents : the best way (but probably not the quickest in the short term) would probably be for each developer to work on his own database instance (see rule #1 for database work).
Installing Oracle on a developer station has become a no brainer since Oracle Database 10g Express Edition.
Have you tried ALTER SYSTEM KILL SESSION? Get the SID and SERIAL# from V$SESSION for each session in the given schema, then do
ALTER SCHEMA KILL SESSION sid,serial#;
just use SQL :
disconnect;
conn tiger/scott as sysdba;

Resources