# 实时查询数据库活动会话状态

# MySQL

-- 查询所有会话
show full processlist;
-- 查询info不为空的
select * from information_schema.processlist where info is not null order by time desc;


-- 查询锁阻塞会话
-- mysql 8.0
SELECT
  b.trx_mysql_thread_id AS `阻塞会话id`,
  b.trx_query AS `阻塞sql`,
  r.trx_mysql_thread_id AS `被阻塞会话id`,
  r.trx_query AS `被阻塞sql`,
  TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS `等待秒`
FROM
  PERFORMANCE_SCHEMA.data_lock_waits w
  JOIN information_schema.innodb_trx r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID
  JOIN information_schema.innodb_trx b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
ORDER BY
  `等待秒` DESC;

-- mysql 5.7
SELECT
  b.trx_mysql_thread_id AS `阻塞会话id`,
  b.trx_query AS `阻塞sql`,
  r.trx_mysql_thread_id AS `被阻塞会话id`,
  r.trx_query AS `被阻塞sql`,
  TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS `等待秒`
FROM
  information_schema.innodb_lock_waits w
  JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
  JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
ORDER BY
  `等待秒` DESC;

# SQl Server

WITH t_proc AS (SELECT spid, count(*) proc_count, max(loginame) loginame FROM sys.sysprocesses GROUP BY spid),
exec_sql_tab AS (SELECT * FROM sys.dm_exec_requests),
h_lock AS (
  SELECT
    a.blocking_session_id AS blocked
  FROM
    exec_sql_tab a
  WHERE
    NOT EXISTS (SELECT 1 FROM exec_sql_tab WHERE blocking_session_id > 0 AND session_id = a.blocking_session_id)
    AND blocking_session_id > 0
  GROUP BY
    a.blocking_session_id
) SELECT
  (CASE WHEN h_lock.blocked IS NOT NULL THEN 1 ELSE 0 END) AS 'headlockflag',
  '"' + (
    CASE
      WHEN substring(dest.TEXT, 1, 16) = 'FETCH API_CURSOR' THEN
        (SELECT t.TEXT FROM sys.dm_exec_cursors (der.session_id) c CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t)
      ELSE
        dest.TEXT
    END
  ) + '"' AS 'SQL语句',
  (CASE WHEN substring(dest.TEXT, 1, 16) = 'FETCH API_CURSOR' THEN 1 ELSE 0 END) AS 'fetch_cursor状态',
  (
    CASE
      WHEN charindex ('<ParameterList>', dest_plan.query_plan) > 0 THEN
        '"' + substring(
          dest_plan.query_plan,
          charindex ('<ParameterList>', dest_plan.query_plan),
          charindex ('</ParameterList>', dest_plan.query_plan) - charindex ('<ParameterList>', dest_plan.query_plan) + 16
        ) + '"'
      ELSE
        ''
    END
  ) AS 'SQL变量绑定参数',
  der.cpu_time AS '运行时间',
  der.session_id AS '会话ID',
  t_proc.proc_count AS '运行线程数',
  der.command AS '命令',
  der.blocking_session_id AS '阻塞其会话的会话ID',
  DB_NAME (der.database_id) AS '数据库名称',
  der.request_id AS '请求ID',
  der.start_time AS '开始时间',
  der.STATUS AS '状态',
  der.READS AS '物理读次数',
  der.writes AS '写次数',
  der.logical_reads AS '逻辑读次数',
  der.row_count AS '返回结果行数',
  der.wait_type AS '等待资源类型',
  der.wait_time AS '等待时间',
  der.total_elapsed_time,
  der.wait_resource AS '等待的资源',
  conn.client_net_address AS '客户端地址',
  tmpdb.user_objects_alloc_page_count AS 'tempdb使用页',
  t_proc.loginame AS '登录用户名',
  der.query_hash AS 'SQL的HASH',
  der.transaction_id,
  der.open_transaction_count,
  der.open_resultset_count,
  CONVERT(CHAR(24), getdate (), 121) AS '采集时刻'
FROM
  exec_sql_tab der
  LEFT JOIN sys.dm_exec_connections conn ON (conn.session_id = der.session_id)
  LEFT JOIN h_lock ON (h_lock.blocked = der.session_id)
  LEFT JOIN t_proc ON (t_proc.spid = der.session_id)
  LEFT JOIN sys.dm_db_session_space_usage tmpdb ON (tmpdb.session_id = der.session_id) CROSS APPLY sys.dm_exec_sql_text (der.sql_handle) AS dest CROSS APPLY sys.dm_exec_text_query_plan (der.plan_handle, DEFAULT, DEFAULT) AS dest_plan
WHERE
  der.session_id <> @@spid
ORDER BY
  'headlockflag' DESC,
  blocking_session_id,
  cpu_time DESC

# Oracle

SELECT
  SUBSTR(sys_connect_by_path (s.INST_ID || '#' || s.SID, '-->'), 4) AS tree_sid,
  S.INST_ID AS inst_id, -- 对于RAC的节点
  S.SID AS sid, -- 会话ID
  S.SERIAL # AS serial,
  S.STATUS AS status, -- 会话状态
  S.MACHINE AS machine, -- 客户端机器名
  S.PROGRAM AS program, -- 客户端运行程序
  S.SQL_ID AS sql_id, -- 执行sql的id
  B.SQL_TEXT AS sql_text, -- 执行sql的文本
  -- (CASE WHEN LENGTHB(B.SQL_TEXT)<3990 THEN TO_CLOB('') ELSE B.SQL_FULLTEXT END) SQL_FULLTEXT, -- sql长度超过3990字节才取fulltext,否则返回空
  S.WAIT_CLASS AS wait_class, -- 等待类型
  S.EVENT AS event, -- 等待事件
  S.SECONDS_IN_WAIT AS seconds_in_wait, --等待时间(秒)
  TO_CHAR(S.SQL_EXEC_START, 'YYYY-MM-DD HH24:MI:SS') sql_exec_start, -- SQL执行开始时间
  TO_CHAR(S.LOGON_TIME, 'YYYY-MM-DD HH24:MI:SS') login_time, -- 会话登录时间
  (SELECT LISTAGG(B.object_name, ',' || CHR(13)) WITHIN GROUP (ORDER BY B.OWNER)
FROM
  GV$LOCKED_OBJECT A,
  DBA_OBJECTS B
WHERE
  A.inst_id = S.inst_id
  AND A.session_id = S.SID
  AND B.owner = S.username
  AND B.object_id = A.object_id
) lock_object_name -- 锁定对象名称
FROM
GV$ SESSION S
LEFT JOIN GV$ SQL B ON (B.INST_ID = S.INST_ID AND B.SQL_ID = S.SQL_ID AND B.CHILD_NUMBER = S.SQL_CHILD_NUMBER)
WHERE
S.TYPE = 'USER'
--and S.sid<>(select sys_context('userenv','sid') from dual)   -- 不含本次查询连接会话
AND (
S.BLOCKING_SESSION IS NOT NULL
OR (S.INST_ID || '#' || S.SID) IN (SELECT DISTINCT BLOCKING_INSTANCE || '#' || BLOCKING_SESSION FROM GV$ SESSION)
OR S.status = 'ACTIVE'
OR (S.status = 'INACTIVE' AND S.TADDR IS NOT NULL)
) START WITH (s.BLOCKING_INSTANCE || '#' || s.BLOCKING_SESSION) = '#' CONNECT BY PRIOR (S.INST_ID || '#' || S.SID) = (s.BLOCKING_INSTANCE || '#' || s.BLOCKING_SESSION)
ORDER BY
TREE_SID

# Postgres

SELECT
  a.pid,
  a.usename,
  a.datname,
  a.client_addr,
  a.STATE,
  a.query,
  now() - a.query_start AS query_duration,
  blocked_count.COUNT AS blocked_count
FROM
  pg_stat_activity a
  JOIN (
    SELECT
      UNNEST(pg_blocking_pids (pid)) AS blocking_pid,
      COUNT(*) AS COUNT
    FROM
      pg_stat_activity
    WHERE
      CARDINALITY (pg_blocking_pids (pid)) > 0
    GROUP BY
      blocking_pid
  ) blocked_count ON a.pid = blocked_count.blocking_pid
ORDER BY
  blocked_count.COUNT DESC;

# DM

-- 查询所有活动会话及其完整SQL
SELECT SF_GET_SESSION_SQL(SESS_ID) AS FULL_SQL, STATE, CLNT_IP
FROM V$SESSIONS WHERE STATE = 'ACTIVE';

-- 查询存在未提交事务的会话完整SQL(常用于排查锁表问题)
SELECT SF_GET_SESSION_SQL(SESS_ID) AS FULLSQL, *
FROM V$SESSIONS
WHERE TRX_ID IN (SELECT ID FROM V$TRX WHERE INS_CNT + DEL_CNT + UPD_CNT + UPD_INS_CNT > 0);

-- 查询会话锁树列表
WITH SESS_TAB AS (
  SELECT
    S.SESS_ID, -- 会话ID
    S.SESS_SEQ AS SERIAL, -- 会话序列号,用来唯一标识会话
    S.STATE, -- 会话状态
    nvl (
      REPLACE(substr(S.CLNT_IP, 1, instr (S.CLNT_IP, ':',- 1) - 1), '::ffff:', ''),
      ''
    ) AS CLNT_IP, -- 客户端机器IP
    S.CURR_SCH, -- 当前模式
    S.SQL_ID, -- 执行sql的id
    S.SQL_TEXT, -- 执行sql的文本,取sql的头1000个字符
    (
      CASE
        WHEN (SELECT COUNT(*) FROM V$SQLTEXT WHERE SQL_ID = S.SQL_ID) > 1 THEN
          (SELECT LISTAGG2 (SQL_TEXT, '') WITHIN GROUP (ORDER BY SQL_NTH) FROM V$SQLTEXT WHERE SQL_ID = S.SQL_ID)
        ELSE
          TO_CLOB ('')
      END
    ) AS SQL_FULLTEXT,
    S.TRX_ID, -- 执行事务ID
    nvl (X.WAIT_FOR_ID,- 1) WAIT_FOR_ID, -- 等待事务ID
    nvl (X.WAIT_SESS_ID,- 1) WAIT_SESS_ID, -- 等待事务所属会话ID
    nvl (X.WAIT_TIME, 0) / 1000 WAIT_TIME, --当前等待时间(豪秒)
    nvl ((SELECT R.NAME FROM SYSOBJECTS R WHERE R.ID = X.WAIT_TABLE_ID), '') WAIT_OBJ_NAME, -- 等待对象名
    TO_CHAR(S.CREATE_TIME, 'YYYY-MM-DD HH24:MI:SS') LOGON_TIME, -- 会话登录时间
    nvl (
      (
        SELECT LISTAGG
          (NAME, ',') WITHIN GROUP (ORDER BY NAME)
        FROM
          SYSOBJECTS
        WHERE
          ID IN (SELECT DISTINCT W.TABLE_ID FROM V$ LOCK W WHERE W.TRX_ID = S.TRX_ID AND W.IGN_FLAG = 0)
          AND SCHID > 0
      ),
      ''
    ) LOCK_OBJECT_NAME -- 操作锁定对象集合
  FROM
    V$SESSIONS S
    LEFT JOIN (
      SELECT
        A.*,
        (SELECT SESS_ID FROM V$TRX WHERE ID = A.WAIT_FOR_ID) AS WAIT_SESS_ID,
        C.WAITING,
        B.TABLE_ID AS WAIT_TABLE_ID
      FROM
        V$TRXWAIT A,
        V$ LOCK B,
        V$TRX C
      WHERE
        B.ADDR = C.WAITING
        AND A.WAIT_FOR_ID = B.TID
        AND A.ID = C.ID
    ) X ON (X.ID = S.TRX_ID)
  WHERE
    S.SESS_ID <> (SELECT sys_context ('userenv', 'sid') FROM dual)
    AND TRX_ID > 0
) SELECT
  1 AS TEST_ID,
  SUBSTR(sys_connect_by_path (T.SESS_ID, '->'), 4) AS TREE_SESS_ID,
  T.*
FROM
  SESS_TAB T START WITH T.WAIT_FOR_ID = - 1 CONNECT BY PRIOR T.TRX_ID = T.WAIT_FOR_ID
ORDER BY
  TREE_SESS_ID;

# KingBase

-- 查询锁阻塞
SELECT
  pid,
  sys_blocking_pids (pid),
  wait_event_type,
  wait_event,
  query
FROM
  sys_stat_activity
WHERE
  STATE = 'active';
编撰人:wangyxyf