ESC را فشار دهید تا بسته شود

زمیوس آموزش، یادگیری و سرگرمی

دستور مشاهده Sessionهای فعال در Oracle؛ کاربران متصل و SQL در حال اجرا

اگر دیتابیس Oracle کند شده، تعداد اتصال‌ها افزایش پیدا کرده یا می‌خواهید بدانید چه کاربرانی به دیتابیس متصل هستند، اولین قدم بررسی Sessionهای فعال Oracle است.

با مشاهده Sessionها می‌توانیم بفهمیم:

  • چه کاربرانی به Oracle متصل‌اند؛
  • هر کاربر از چه سیستم و برنامه‌ای وصل شده است؛
  • کدام Session فعال یا غیرفعال است؛
  • هر Session چه دستور SQLای اجرا می‌کند؛
  • کدام Session مدت زیادی مشغول اجراست؛
  • چه Sessionهایی یکدیگر را قفل کرده‌اند؛
  • چگونه یک Session مشکل‌ساز را متوقف کنیم.

در این مقاله آموزش اوراکل از بخش CheatSheet، مهم‌ترین و کاربردی‌ترین کوئری‌های مدیریت Session در Oracle را به‌صورت خلاصه و عملی بررسی می‌کنیم.

اگر با Oracle Database کار می‌کنید، احتمالاً خیلی زود به این نتیجه می‌رسید که فقط بلد بودن چند دستور SELECT و JOIN کافی نیست.

در دنیای واقعی، چیزی که تفاوت ایجاد می‌کند این است که بتوانید کوئری درست، سریع، قابل نگهداری و بهینه بنویسید.

پیشنهاد می کنم این مقاله زیر رو حتما مطالعه کنی.

در این مقاله شما می خوانید

Session در Oracle چیست؟

هر زمان یک کاربر، برنامه یا سرویس به دیتابیس Oracle متصل می‌شود، یک Session ایجاد می‌شود.

برای مثال، اتصال از طریق ابزارها و سرویس‌های زیر می‌تواند یک یا چند Session بسازد:

  • Oracle SQL Developer
  • SQL*Plus و SQLcl
  • Oracle APEX و ORDS
  • JDBC
  • WebLogic
  • نرم‌افزارهای سازمانی
  • Connection Pool برنامه‌ها

اطلاعات Sessionهای Oracle عمدتاً در View سیستمی زیر نگهداری می‌شود:

				
					V$SESSION

				
			

در محیط Oracle RAC باید از نسخه سراسری این View استفاده کنیم:

				
					GV$SESSION

				
			

مشاهده کاربران متصل به Oracle

برای مشاهده همه Sessionهای کاربری متصل به Instance فعلی، از کوئری زیر استفاده کنید:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.osuser,
    s.machine,
    s.program,
    s.module,
    s.service_name,
    s.logon_time
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
ORDER BY s.logon_time DESC;

				
			

معنی ستون‌های مهم

ستون توضیح
SID شناسه Session
SERIAL# شماره تکمیلی برای شناسایی دقیق Session
USERNAME نام کاربر Oracle
STATUS وضعیت فعال یا غیرفعال Session
OSUSER نام کاربر سیستم‌عامل مبدأ
MACHINE نام سیستم یا سرور مبدأ
PROGRAM برنامه ایجادکننده اتصال
MODULE ماژول معرفی‌شده توسط برنامه
SERVICE_NAME سرویس Oracle مورد استفاده
LOGON_TIME زمان برقراری اتصال

تفاوت Session فعال و غیرفعال در Oracle

وضعیت هر Session در ستون STATUS نمایش داده می‌شود. مهم‌ترین مقادیر آن عبارت‌اند از:

  • ACTIVE: Session در حال اجرای یک Call است یا منتظر منبعی مانند Lock و I/O مانده است.
  • INACTIVE: اتصال همچنان برقرار است، اما SQL فعالی اجرا نمی‌شود.
  • KILLED: Session برای خاتمه علامت‌گذاری شده است.
  • SNIPED: Session معمولاً به دلیل محدودیت‌هایی مانند IDLE_TIME منقضی شده است.

نکته مهم این است که ACTIVE بودن همیشه به معنای مصرف CPU نیست. ممکن است Session فعال باشد، اما منتظر قفل، دیسک، شبکه یا منبع دیگری مانده باشد.

مشاهده Sessionهای فعال Oracle

کوئری مشاهده Sessionهای فعال در Oracle

برای مشاهده Sessionهای فعال Oracle از کوئری زیر استفاده کنید:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.osuser,
    s.machine,
    s.program,
    s.module,
    s.service_name,
    s.sql_id,
    s.event,
    s.wait_class,
    s.state,
    s.seconds_in_wait,
    s.last_call_et AS call_elapsed_seconds,
    s.logon_time
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
ORDER BY s.last_call_et DESC;

				
			

کوئری جامع مشاهده Sessionهای فعال Oracle

اگر بخواهیم اطلاعات اتصال، SQL جاری، وضعیت انتظار و Process سیستم‌عامل را در یک گزارش داشته باشیم، کوئری زیر انتخاب مناسبی است:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.osuser,
    s.machine,
    s.program,
    s.module,
    s.action,
    s.client_identifier,
    s.service_name,
    s.sql_id,
    s.sql_child_number,
    s.event,
    s.wait_class,
    s.state,
    s.seconds_in_wait,
    s.last_call_et AS call_elapsed_seconds,
    s.logon_time,
    p.spid AS server_os_pid,
    q.sql_text
FROM v$session s
LEFT JOIN v$process p
       ON p.addr = s.paddr
LEFT JOIN v$sql q
       ON q.sql_id = s.sql_id
      AND q.child_number = s.sql_child_number
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
  AND s.audsid <> SYS_CONTEXT('USERENV', 'SESSIONID')
ORDER BY s.last_call_et DESC;

				
			

با این گزارش می‌توانیم بفهمیم:

  1. چه کاربری به دیتابیس متصل است؛
  2. اتصال از کدام سیستم ایجاد شده است؛
  3. کاربر از چه برنامه یا ماژولی استفاده می‌کند؛
  4. کدام SQL در حال اجراست؛
  5. Call جاری چه مدت ادامه داشته است؛
  6. Session منتظر چه رویدادی است؛
  7. Process مربوط به آن در سیستم‌عامل سرور چیست.

مشاهده SQL در حال اجرای Sessionهای Oracle

برای مشاهده متن SQL جاری باید اطلاعات V$SESSION را به V$SQL متصل کنیم:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.module,
    s.sql_id,
    s.sql_child_number,
    s.event,
    s.wait_class,
    s.last_call_et AS call_elapsed_seconds,
    q.sql_text
FROM v$session s
LEFT JOIN v$sql q
       ON q.sql_id = s.sql_id
      AND q.child_number = s.sql_child_number
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
ORDER BY s.last_call_et DESC;

				
			

مشاهده متن کامل SQL در Oracle

ستون SQL_TEXT ممکن است فقط بخشی از دستور را نمایش دهد. برای دریافت متن کامل‌تر می‌توانیم از SQL_FULLTEXT استفاده کنیم:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    s.sql_id,
    q.sql_fulltext
FROM v$session s
JOIN v$sql q
  ON q.sql_id = s.sql_id
 AND q.child_number = s.sql_child_number
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE';

				
			

پیدا کردن Sessionهای یک کاربر خاص

برای مشاهده Sessionهای کاربر HR از کوئری زیر استفاده کنید:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.osuser,
    s.machine,
    s.program,
    s.module,
    s.sql_id,
    s.logon_time,
    s.last_call_et
FROM v$session s
WHERE s.type = 'USER'
  AND s.username = 'HR'
ORDER BY s.logon_time DESC;

				
			

شناسایی اتصال بر اساس سیستم یا برنامه

جست‌وجو بر اساس سیستم مبدأ

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.osuser,
    s.program,
    s.module,
    s.logon_time
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND UPPER(s.machine) LIKE UPPER('%APP-SERVER%')
ORDER BY s.logon_time DESC;

				
			

جست‌وجو بر اساس برنامه

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.module
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND UPPER(s.program) LIKE '%SQL DEVELOPER%';

				
			

شناسایی Sessionهای APEX

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.module,
    s.action,
    s.client_identifier,
    s.service_name
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND (
        UPPER(s.module) LIKE '%APEX%'
        OR UPPER(s.program) LIKE '%ORDS%'
      );

				
			

شمارش Sessionهای Oracle

تعداد کل Sessionهای متصل

				
					SELECT COUNT(*) AS connected_sessions
FROM v$session
WHERE type = 'USER'
  AND username IS NOT NULL;

				
			

تعداد Sessionهای فعال

				
					SELECT COUNT(*) AS active_sessions
FROM v$session
WHERE type = 'USER'
  AND username IS NOT NULL
  AND status = 'ACTIVE';

				
			

تعداد Sessionها به تفکیک کاربر و وضعیت

				
					SELECT
    username,
    status,
    COUNT(*) AS session_count
FROM v$session
WHERE type = 'USER'
  AND username IS NOT NULL
GROUP BY username, status
ORDER BY session_count DESC, username, status;

				
			

توجه داشته باشید که تعداد Sessionها با تعداد کاربران واقعی برابر نیست. یک کاربر دیتابیس می‌تواند چند اتصال هم‌زمان داشته باشد، مخصوصاً در محیط‌های دارای Connection Pool.

پیدا کردن Sessionهای طولانی‌مدت

برای مشاهده Sessionهایی که Call جاری آن‌ها بیش از پنج دقیقه زمان برده است:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    s.module,
    s.sql_id,
    s.event,
    s.wait_class,
    s.state,
    s.last_call_et AS call_elapsed_seconds
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
  AND s.last_call_et > ۳۰۰
ORDER BY s.last_call_et DESC;

				
			

مشاهده Sessionهای غیرفعال قدیمی

کوئری زیر Sessionهایی را نشان می‌دهد که بیشتر از یک ساعت غیرفعال بوده‌اند:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.module,
    s.logon_time,
    s.last_call_et AS inactive_seconds
FROM v$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'INACTIVE'
  AND s.last_call_et > ۳۶۰۰
ORDER BY s.last_call_et DESC;

				
			

مشاهده Transactionهای باز

پیش از بستن یک Session بهتر است بررسی کنیم که Transaction باز دارد یا خیر:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.sql_id,
    t.start_time AS transaction_start_time,
    t.used_ublk AS undo_blocks,
    t.used_urec AS undo_records
FROM v$session s
JOIN v$transaction t
  ON t.addr = s.taddr
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
ORDER BY t.start_time;

				
			

شناسایی Sessionهای قفل‌شده و قفل‌کننده

برای مشاهده Sessionهایی که منتظر Session دیگری هستند، می‌توانیم از BLOCKING_SESSION استفاده کنیم:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.sql_id,
    s.event,
    s.wait_class,
    s.seconds_in_wait,
    s.blocking_session_status,
    s.blocking_instance,
    s.blocking_session
FROM v$session s
WHERE s.blocking_session IS NOT NULL
ORDER BY s.seconds_in_wait DESC;

				
			

برای نمایش مشخصات Session قفل‌شده و قفل‌کننده در محیط Single Instance:

				
					SELECT
    blocked.sid              AS blocked_sid,
    blocked.serial#          AS blocked_serial,
    blocked.username         AS blocked_user,
    blocked.sql_id           AS blocked_sql_id,
    blocked.event            AS blocked_event,
    blocked.seconds_in_wait,
    blocker.sid              AS blocker_sid,
    blocker.serial#          AS blocker_serial,
    blocker.username         AS blocker_user,
    blocker.machine          AS blocker_machine,
    blocker.program          AS blocker_program,
    blocker.sql_id           AS blocker_sql_id
FROM v$session blocked
JOIN v$session blocker
  ON blocker.sid = blocked.blocking_session
WHERE blocked.blocking_session IS NOT NULL
ORDER BY blocked.seconds_in_wait DESC;

				
			

مشاهده Sessionهای فعال در Oracle RAC

برای مشاهده Sessionهای تمام Instanceها باید از GV$SESSION استفاده کنیم:

				
					SELECT
    s.inst_id,
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    s.module,
    s.service_name,
    s.sql_id,
    s.event,
    s.wait_class,
    s.last_call_et AS call_elapsed_seconds,
    s.logon_time
FROM gv$session s
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
ORDER BY s.last_call_et DESC;

				
			

در Oracle RAC، شناسایی کامل Session بر اساس ترکیب زیر انجام می‌شود:

				
					INST_ID + SID + SERIAL#

				
			

مشاهده Sessionهای فعال در Oracle RAC به همراه SQL

				
					SELECT
    s.inst_id,
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.osuser,
    s.machine,
    s.program,
    s.module,
    s.service_name,
    s.sql_id,
    s.event,
    s.wait_class,
    s.state,
    s.last_call_et AS call_elapsed_seconds,
    p.spid AS server_os_pid,
    q.sql_text
FROM gv$session s
LEFT JOIN gv$process p
       ON p.inst_id = s.inst_id
      AND p.addr = s.paddr
LEFT JOIN gv$sql q
       ON q.inst_id = s.inst_id
      AND q.sql_id = s.sql_id
      AND q.child_number = s.sql_child_number
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
ORDER BY s.last_call_et DESC;

				
			

نحوه بستن Session در Oracle

بعد از شناسایی دقیق Session می‌توانیم آن را با دستور زیر خاتمه دهیم:

				
					ALTER SYSTEM KILL SESSION 'SID,SERIAL#' IMMEDIATE;

				
			

مثال:

				
					ALTER SYSTEM KILL SESSION '123,45678' IMMEDIATE;

				
			

تولید خودکار دستور Kill Session

کوئری زیر دستور Kill را برای Sessionهای کاربر HR تولید می‌کند:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    'ALTER SYSTEM KILL SESSION '''
    || s.sid
    || ','
    || s.serial#
    || ''' IMMEDIATE;' AS kill_command
FROM v$session s
WHERE s.type = 'USER'
  AND s.username = 'HR';

				
			

بستن Session در Oracle RAC

در محیط RAC باید INST_ID را نیز مشخص کنیم:

				
					ALTER SYSTEM KILL SESSION 'SID,SERIAL#,@INST_ID' IMMEDIATE;

				
			

مثال:

				
					ALTER SYSTEM KILL SESSION '123,45678,@2' IMMEDIATE;

				
			

دسترسی‌های لازم برای مشاهده Sessionهای Oracle

اگر کاربر اجازه مشاهده Dynamic Performance Viewها را نداشته باشد، ممکن است با خطای زیر مواجه شود:

				
					ORA-00942: table or view does not exist

				
			

DBA می‌تواند حداقل دسترسی‌های لازم را اعطا کند:

				
					GRANT SELECT ON v_$session TO report_user;
GRANT SELECT ON v_$process TO report_user;
GRANT SELECT ON v_$sql TO report_user;
GRANT SELECT ON v_$transaction TO report_user;

				
			

برای بستن Session نیز مجوز زیر لازم است:

				
					GRANT ALTER SYSTEM TO admin_user;

				
			

سوالات متداول درباره مشاهده Sessionهای فعال در Oracle

SELECT
sid,
serial#,
username,
status,
machine,
program,
logon_time
FROM v$session
WHERE type = ‘USER’
AND username IS NOT NULL
ORDER BY logon_time DESC;

شرط زیر را به کوئری اضافه کنید:

AND status = ‘ACTIVE’

خیر. یک Session فعال ممکن است روی CPU باشد یا منتظر Lock، I/O، شبکه و منابع دیگر بماند. برای تحلیل دقیق باید EVENT، WAIT_CLASS، STATE و SQL_ID را نیز بررسی کنید.

خیر. Sessionهای INACTIVE در Connection Poolها معمولاً طبیعی هستند. قبل از Kill باید برنامه مبدأ، مدت غیرفعال‌بودن و وجود Transaction باز بررسی شود.

SID شناسه Session است و SERIAL# کمک می‌کند Session فعلی از Session قبلی با همان SID تشخیص داده شود.

برای Kill کردن یک Session به هر دو مقدار نیاز داریم.

جمع‌بندی

برای مشاهده سریع کاربران متصل به Oracle این کوئری کافی است:

				
					SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    s.module,
    s.sql_id,
    s.event,
    s.wait_class,
    s.state,
    s.last_call_et AS call_elapsed_seconds,
    q.sql_text
FROM v$session s
LEFT JOIN v$sql q
       ON q.sql_id = s.sql_id
      AND q.child_number = s.sql_child_number
WHERE s.type = 'USER'
  AND s.username IS NOT NULL
  AND s.status = 'ACTIVE'
  AND s.audsid <> SYS_CONTEXT('USERENV', 'SESSIONID')
ORDER BY s.last_call_et DESC;

				
			

سؤالی درباره این مقاله داری؟

اگر نکته‌ای در این مقاله برات مبهم بود یا خواستی بیشتر بدونی، همین حالا برام بنویس تا دقیق و صمیمی پاسخت رو بدم — مثل یه گفت‌وگوی واقعی 💬

برو به صفحه پرسش و پاسخ

میثم راد

من یه برنامه نویسم که حسابی با دیتابیس اوراکل رفیقم! از اونایی ام که تا چیزی رو کامل نفهمم،ول کن نیستم، یادگرفتن برام مثل بازیه، و نوشتن اینجا کمک می کنه تا چیزایی که یاد گرفتم رو با بقیه به شریک بشم، با هم پیشرفت کنیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *