oracle数据库卡顿排查
最近工作中总是遇到现网操作卡顿的问题,利用deepseek查找一些测试思路。【侵删】
1、通过top命令查询数据库节点负载情况;
2、通过shell命令查询数据库连接数;
3、查询数据库有无死锁情况;
第一步
sql
--查询oracle版本号和已安装组件,执行python连接时需要下载oracle client;
SELECT * FROM V$VERSION;
--查询指定表的所有列名,便于插入sql数据,下方python代码编写时需要;
SELECT LISTAGG(COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY COLUMN_ID) AS column_list
FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = 'ABC' ;
--数据库中所有表按逻辑读次数(访问频率)从高到低排序的统计结果,用于识别数据库中最频繁访问的热点表。也可用作性能分析,将这些表数据量增多,测试下功能交互是否卡顿。
SELECT owner, object_name, value AS logical_reads FROM v$segment_statistics WHERE statistic_name='logical reads' AND object_type='TABLE' ORDER BY value DESC ;
测试环境和现网的数据量不是一个等级,通过第三个sql查出来哪些表最频繁访问,然后先把这些表的数据构造到和现网数据量一个等级。构造方式是通过对当前表中所有数据进行翻倍。python代码如下:
python
import cx_Oracle
DB_CONFIG = {
'host': '192.168.xxx.xxx',
'port': 1521,
'user': 'abc',
'password': 'password',
'database': 'oracledb'
}
dsn = cx_Oracle.makedsn(DB_CONFIG['host'], DB_CONFIG['port'], service_name=DB_CONFIG['database'])
print(f"正在连接: {DB_CONFIG['user']}@{DB_CONFIG['host']}:{1521}/{'paidb'}")
print("-" * 50)
try:
# 建立连接
connection = cx_Oracle.connect(DB_CONFIG['user'], DB_CONFIG['password'], dsn)
print("✅ 数据库连接成功!")
# 创建游标
cursor = connection.cursor()
a=1
# 这里的id加的数值要根据表的sequence决定,测试结束后记得删除构造的数据;
for num in range(100000000000, 399000000001, 1000000000): # 这是插入300倍数据,总数301倍
print(f"num={num}")
# a+=1
# print(a)
sql_job = f'''INSERT INTO {Table1}
SELECT ID + {num}, 字段1,字段2.. FROM {Table1} WHERE ID <= 25766729'''
print(f'执行sql是{sql_job}')
cursor.execute(sql_job)
rows_inserted = cursor.rowcount
connection.commit()
print(f"✅ {Table1}表成功插入 {rows_inserted} 条记录!")
# 关闭游标和连接
cursor.close()
connection.close()
print("-" * 50)
print("✅ 所有测试通过!")
except cx_Oracle.DatabaseError as e:
error_obj, = e.args
print(f"❌ 数据库错误: {error_obj.code} - {error_obj.message}")
except Exception as e:
print(f"❌ 连接失败: {e}")
第二步
通过业务关系分析和这些表有关的一些交互操作或spark作业,也可从代码中查询和创建数据库连接接口有关的工程,分析这些工程中对应的功能操作。
sql
--V$SESSION 是 Oracle 动态性能视图。按会话的 MODULE(模块名)分组,统计每个模块当前有多少个数据库会话,并按会话数从多到少排序。
SELECT count(*) AS cnt , MODULE FROM V$SESSION GROUP BY MODULE ORDER BY CNT DESC;
--查询当前 Oracle 实例中,非后台会话、客户端程序名以 java@ 开头、并且其 MODULE 属于"包含 java 且会话数大于 1"的模块,(**java的一般是计算进程**)
--并列出这些会话的客户端机器、客户端进程、服务器进程、上一个 SQL ID / 当前 SQL ID / 上一个 SQL 文本、模块名,并按登录时间倒序排列。
SELECT
s.machine,
s.program,
s.process AS client_pid,
p.spid AS server_spid,
s.prev_sql_id,
s.sql_id,
q.sql_text,
s.module
FROM v$session s
JOIN v$process p ON s.paddr = p.addr
LEFT JOIN v$sql q
ON s.prev_sql_id = q.sql_id
AND s.prev_child_number = q.child_number
WHERE s.type <> 'BACKGROUND' and s.program like 'java@%' AND s.module IN (
SELECT MODULE
FROM v$session
WHERE MODULE LIKE '%java%'
GROUP BY MODULE
HAVING COUNT(*) > 1
) ORDER BY s.logon_time DESC;
当提交spark作业后,后台数据库监控第二个sql执行结果(通过python实现实时监控),当会话数大于1时,记录下执行的sql。建议多节点执行spark作业并记录下来sql语句是发生在driver节点还是executor节点,便于研发定位问题,查询结果如下图示例:

数据库性能分析的其它sql:
sql
--当前数据库中活跃会话的总数量,用于快速评估数据库当前的实时并发负载压力
SELECT count(*) FROM v$session WHERE status = 'ACTIVE';
--查询当前数据库中所有活跃的非后台用户会话及其正在执行的SQL语句详情(包括SQL文本、登录信息、程序来源等),用于实时监控数据库的当前操作负载
SELECT
s.sid, s.serial#,
s.username,
s.status,
s.sql_id,
s.prev_sql_id,
q.sql_text,
s.program,
s.machine,
s.logon_time
FROM
v$session s
LEFT JOIN
v$sql q ON s.sql_id = q.sql_id
WHERE
--s.status = 'ACTIVE' AND -- 筛选活跃会话
s.type != 'BACKGROUND' -- 排除后台进程
AND s.sql_id IS NOT NULL;
--查询指定SQL_ID(cm5vu20fhtnq1)在历史中的每次活跃会话采样记录,包括执行时间、客户端信息、应用模块等上下文,用于追溯该SQL的历史性能问题或排查谁在何时执行过它。
SELECT
c.username, -- 数据库用户名
a.SAMPLE_TIME, -- 采样时间,帮你定位高峰期
a.MODULE, -- 应用模块名,非常有用的线索
a.ACTION, -- 模块下的动作
a.PROGRAM, -- 连接的程序名,比如 JDBC Thin Client
a.MACHINE, -- 客户端机器名
a.SQL_EXEC_START -- SQL执行开始时间
FROM
DBA_HIST_ACTIVE_SESS_HISTORY a,
DBA_HIST_SQLTEXT b,
DBA_USERS c
WHERE
a.SQL_ID = 'cm5vu20fhtnq1' -- 替换为第一步查到的SQL_ID
AND a.SQL_ID = b.SQL_ID(+)
AND a.USER_ID = c.USER_ID
ORDER BY
a.SAMPLE_TIME DESC;
--以下这两段SQL是Oracle数据库中排查锁问题的经典组合,分别从"谁在等谁"和"锁住了什么对象"两个维度入手:
-- 签署锁的持有者(Holder)和等待者(Waiter)
SELECT DECODE(l.request, 0, 'Holder:', 'Waiter: ') || s.sid || ',' || s.serial# sess,
l.id1,
l.id2,
l.type,
l.lmode,
l.request,
s.username,
s.sql_id,
s.event
FROM v$lock l, v$session s
WHERE (l.id1, l.id2, l.type) IN (SELECT id1, id2, type FROM v$lock WHERE request > 0)
AND l.sid = s.sid
ORDER BY l.id1, l.ctime DESC, l.request;
--查看被锁定的具体对象
SELECT lo.session_id, lo.oracle_username, ao.object_name, lo.locked_mode FROM v$locked_object lo, dba_objects ao WHERE ao.object_id = lo.object_id;