Betrifft: Oracle-Threads unter Win32-Systemen killen Autor: Dirk Nachbar Art der Info: Technische Background Info Quelle: Aus unserer Projekterfahrung Einleitung Von Zeit zu Zeit muss ein Oracle DBA eine Session eines Users killen und verwendet zumeist den SQL-Befehl „alter system kill session ...“. Unter den meisten Umständen ist die Antwortzeit für diesen Vorgang zu lang und auch oftmals wird nach Beendigung des „kill session“-Befehls das Problem nicht sofort bereinigt (CPU-Belastung usw.). Eine weitere Variante die Problemsession zu beenden ist den Oracle Service zu beenden oder via den Task-Manager den gesamten Oracle-Prozess zu beenden, was zumeist als letzte Notlösung verwendet wird und zur Folge hat, dass alle Usersessions beendet werden . Ein prägnanter Unterschied zwischen Oracle unter UNIX-Derivaten und Windows Plattformen ist die Prozessstruktur. Unter UNIX Derivaten lassen sich problemlos alle Oracle Prozesse auflisten (ps-Befehl) und explizit beenden (kill -9), aber unter Windows Plattformen sieht man nur einen „großen“ Oracle Prozess, welcher sich in mehrere Threads unterteilt. Aber auch hierfür stellt Oracle Tools zur Verfügung um einzelne Threads zu killen, ohne gleich die gesamte Instanz zu stoppen. Diese Threads lassen sich zwar auch mittels diverser Tools darstellen, aber wie findet man nun den entsprechenden Thread eindeutig heraus? Administration Assistant for Windows Oracle bietet mittels dem Administration Assistent for Windows eine grafische Möglichkeit sich die Oracle Threads anzeigen zu lassen und explizit zu „killen“. Über das Kontextmenü „Prozessinformationen ...“ erhält mal eine ziemlich detailiierte Auflistung der aktuellen Threads mit Programmnamen, Typ, Oracle-Benutzer, Thread-ID und CPU-Belastung. Hier muss man nur den entsprechenden Thread markieren und sodann den Button „Thread abbrechen“ betätigen. In Umgebungen, in denen jeder Anwender mit seinem eigenen Oracle-Benutzer sich an die Datenbank anmeldet ist dieses Tool eine gute Wahl, doch in einigen Umgebungen melden sich die Anwender mit nur einem Oracle-Benutzer an, so dass man keine Chance hat mittels dieses Tools den richtigen Thread zu killen. Orakill – CommandLine Utility Bereits seit Oracle 7.3 gibt es unter Windows das kaum beachtete Command-Line Utility orakill. C:\> orakill -? Usage: orakill sid thread where sid = the Oracle instance to target thread = the thread id of the thread to kill The thread id should be retrieved from the spid column of a query such as: select spid, osuser, s.program from v$process p, v$session s where p.addr=s.paddr C:\> Führt man das oben angeführte SQL Script aus, erhält man zwar die Thread ID (spid), den Betriebssystembenutzer und das Programm welche zu dem Thread gehören, aber jedoch nicht den Oraclebenutzer bzw. den Oracleprozess (PMON, SMON usw) und die ClientWorkstation. SQL> select spid, osuser, s.program from 2 v$process p, v$session s where p.addr=s.paddr; SPID -------- OSUSER ------------------- PROGRAM -------------------- 300 1468 .. .. .. 2488 2492 2496 2504 2512 2532 1544 2304 SYSTEM SYSTEM ORACLE.EXE ORACLE.EXE TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\din TRIVADIS\din TRIVADIS\din JRE.EXE JRE.EXE JRE.EXE JRE.EXE JRE.EXE MMC.EXE SQLPLUS.EXE SQLPLUS.EXE 28 Zeilen ausgewählt Erweitern man das Statement wie nachfolgend dargestellt, erhält man alle „Oracle Threads“ und die Angabe der Client-Workstation. SQL> select p.spid "OS Th", b.name "Name-User", s.osuser, 2 s.program, s.terminal 3 from v$process p, v$session s, v$bgprocess b 4 where p.addr = s.paddr 5 and p.addr = b.paddr UNION ALL 6 select p.spid "OS Th", s.username "Name-User", 7 s.osuser, s.program, s.terminal 8 from v$process p, v$session s 9 where p.addr = s.paddr 10 and s.username is not null; OS Th ----- Name-User -------------- OSUSER -------------- PROGRAM ------------ TERMINAL ---------- 300 1468 .. .. .. 2488 2492 2496 2504 2512 2532 1544 2304 PMON DBW0 SYSTEM SYSTEM ORACLE.EXE ORACLE.EXE LTDIN LTDIN OEM_LTDIN_PROD OEM_LTDIN_PROD OEM_LTDIN_PROD OEM_LTDIN_PROD OEM_LTDIN_PROD OEM_LTDIN_PROD SCOTT SCOTT TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\LTDIN$ TRIVADIS\din TRIVADIS\din TRIVADIS\din JRE.EXE JRE.EXE JRE.EXE JRE.EXE JRE.EXE MMC.EXE SQLPLUS.EXE SQLPLUS.EXE LTDIN LTDIN LTDIN LTDIN LTDIN LTDIN LTDIN LTTEST 28 Zeilen ausgewählt Nun ist der DBA in der Lage, den gesuchten Thread eindeutig zu identifizieren und zu „killen“, auch wenn sich der Anwender von mehreren Client-Workstations aus mit dem gleichen Betriebssystembenutzer connected hat. C:\> orakill PROD 1544 Kill of thread id 1544 in instance PROD successfully signalled. C:\> Versucht der Benutzer nach dem „Thread-Kill“ eine Aktion auf der Datenbank, erhält er folgende Fehlermeldung: SQL> select * from dual; select * from dual * FEHLER in Zeile 1: ORA-12571: TNS:packet writer failure Erweitert man das oben stehende Statement folgendermassen, werden alle Threads angezeigt und interaktiv wird ein Commandline-Batch erzeugt, welcher eine Nachricht via „net send“ an die entsprechende Client-Workstation sendet das seine Datenbankverbindung beendet wird und anschliessend der ausgewählte Thread mittels orakill beendet wird. select p.spid "OS Th", b.name "Name-User", s.osuser, s.program, s.terminal from v$process p, v$session s, v$bgprocess b where p.addr = s.paddr and p.addr = b.paddr UNION ALL select p.spid "OS Th", s.username "Name-User", s.osuser, s.program, s.terminal from v$process p, v$session s where p.addr = s.paddr and s.username is not null; set echo off set feedback off set verify off ACCEPT threadid PROMPT 'Please enter Thread ID (spid): ' ACCEPT sid PROMPT 'Please enter SID: ' set termout off set heading off spool kill_thread.bat select 'net send '||s.terminal||' Your Database Connect will be closed' from v$process p, v$session s where p.addr=s.paddr and spid=&threadid / select 'orakill &sid '||spid||'' from v$process where spid=&threaded / spool off set heading on set termout on PROMPT Commandline Batch is finished and named kill_thread.bat Diese Methode funktioniert von Oracle 7.3.x bis hoch zur aktuellen Oracle 9i. Hinweis: Das Oracle Utility orakill verwendet den Systemaufruf TerminateThread(). Dieser Aufruf bewirkt nicht, dass der Stackbereich freigegeben wird. Doch dieser Stackbereich bleibt allozier- und verwendbar für den Oracle-Prozess. ☺ Falls Sie noch mehr über Oracle 9i erfahren wollen, dann würde es uns freuen, Sie in einem unserer 9i-Kurse (NF9i, AI9-A, AI9-B) begrüßen zu dürfen. Viel Spaß und wenige zu killende Threads wünscht Dirk Nachbar Trivadis GmbH Dirk Nachbar Cityforum im Eichsfeld Ferdinand-Stuttmann-Str. 13 D-65428 Rüsselsheim Internet: http://www.trivadis.com Mail: [email protected] Tel: Fax: +49 6142 210 18 0 +49 6142 210 18 29