未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用边界与维护说明
本文适合已有Oracle动态性能视图、PL/SQL和Scheduler基础的读者研究实例、SQL、等待与锁监控的组织方式,不是可直接部署的银行生产监控方案。本次仅作全文结构与代码逻辑审阅,未作外部事实核验或数据库运行验证。当前仍有累计CPU时间被当作使用率、累计快照直接求和、SQL子游标采集主键冲突、锁对象及阻塞关系误判、TPS参数与诊断除法缺少保护等问题;所列作业未采集等待与锁历史,等待历史为空时报告可能中断。部署前还需补足transaction_log结构与交易计数口径、对象访问及包编译所需权限、FETCH FIRST版本要求和依赖对象创建顺序。业务响应视图仅是文本匹配游标平均耗时的非加权平均,不能代表端到端响应;锁报告的记录数不能直接视为独立等待事件次数。示例未覆盖RAC跨实例及CDB容器维度,UNDO大小按8KB块估算,每日增长1%是显式假设,固定阈值需结合实际负载评估,不能据此承诺生产告警准确性或业务稳定性。
Oracle性能监控与诊断
性能监控概述
Oracle数据库性能监控是确保银行系统稳定运行的关键环节。通过建立完善的监控体系,可以及时发现性能瓶颈、预防系统故障,并为性能优化提供数据支撑。
1. 性能监控层次
系统级监控
- CPU使用率、内存使用情况
- 磁盘I/O性能、网络带宽
- 操作系统资源利用率
实例级监控
- SGA内存区域使用情况
- 后台进程状态
- 等待事件统计
SQL级监控
- SQL执行时间、执行次数
- 执行计划变化
- 资源消耗统计
会话级监控
- 用户会话状态
- 锁等待情况
- 事务处理性能
核心性能视图和指标
1. 实例性能监控
-- 实例总体性能视图
CREATE OR REPLACE VIEW v_instance_performance AS
SELECT
i.instance_name,
i.host_name,
i.startup_time,
ROUND((SYSDATE - i.startup_time) * 24, 2) as uptime_hours,
s1.value as user_commits,
s2.value as user_rollbacks,
s3.value as physical_reads,
s4.value as logical_reads,
ROUND(s4.value / NULLIF(s3.value, 0), 2) as logical_to_physical_reads_ratio,
s5.value as redo_size,
s6.value as sorts_memory,
s7.value as sorts_disk,
ROUND(s6.value / NULLIF(s6.value + s7.value, 0) * 100, 2) as sort_memory_pct
FROM
v$instance i,
v$sysstat s1,
v$sysstat s2,
v$sysstat s3,
v$sysstat s4,
v$sysstat s5,
v$sysstat s6,
v$sysstat s7
WHERE
s1.name = 'user commits' AND
s2.name = 'user rollbacks' AND
s3.name = 'physical reads' AND
s4.name = 'session logical reads' AND
s5.name = 'redo size' AND
s6.name = 'sorts (memory)' AND
s7.name = 'sorts (disk)';
-- 内存使用情况监控
CREATE OR REPLACE VIEW v_memory_usage AS
SELECT
'SGA' as memory_type,
ROUND(SUM(value) / 1024 / 1024, 2) as size_mb
FROM v$sga
UNION ALL
SELECT
'PGA' as memory_type,
ROUND(value / 1024 / 1024, 2) as size_mb
FROM v$pgastat
WHERE name = 'total PGA allocated'
UNION ALL
SELECT
component,
ROUND(current_size / 1024 / 1024, 2) as size_mb
FROM v$memory_dynamic_components
WHERE current_size > 0
ORDER BY size_mb DESC;
-- 等待事件监控
CREATE OR REPLACE VIEW v_wait_events AS
SELECT
event,
total_waits,
time_waited,
ROUND(time_waited / NULLIF(total_waits, 0), 2) as avg_wait_time,
ROUND(time_waited * 100 / SUM(time_waited) OVER(), 2) as pct_time
FROM v$system_event
WHERE event NOT LIKE '%message%'
AND event NOT LIKE '%timer%'
AND time_waited > 0
ORDER BY time_waited DESC;
2. SQL性能监控
-- TOP SQL监控视图
CREATE OR REPLACE VIEW v_top_sql AS
SELECT
sql_id,
plan_hash_value,
executions,
ROUND(elapsed_time / 1000000, 2) as elapsed_seconds,
ROUND(cpu_time / 1000000, 2) as cpu_seconds,
ROUND(user_io_wait_time / 1000000, 2) as io_wait_seconds,
buffer_gets,
disk_reads,
ROUND(buffer_gets / NULLIF(executions, 0), 2) as gets_per_exec,
ROUND(disk_reads / NULLIF(executions, 0), 2) as reads_per_exec,
ROUND(elapsed_time / NULLIF(executions, 0) / 1000000, 3) as avg_elapsed_seconds,
last_active_time
FROM v$sql
WHERE executions > 0
AND elapsed_time > 0
ORDER BY elapsed_time DESC;
-- SQL文本查询
CREATE OR REPLACE FUNCTION get_sql_text(p_sql_id VARCHAR2)
RETURN CLOB AS
v_sql_text CLOB;
BEGIN
SELECT sql_fulltext
INTO v_sql_text
FROM v$sql
WHERE sql_id = p_sql_id
AND ROWNUM = 1;
RETURN v_sql_text;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'SQL not found in memory';
END get_sql_text;
/
-- 银行业务SQL性能监控
CREATE OR REPLACE VIEW v_banking_sql_performance AS
SELECT
s.sql_id,
s.executions,
ROUND(s.elapsed_time / 1000000, 2) as elapsed_seconds,
ROUND(s.elapsed_time / s.executions / 1000000, 3) as avg_elapsed_seconds,
s.buffer_gets,
s.disk_reads,
CASE
WHEN UPPER(st.sql_text) LIKE '%CUSTOMER_INFO%' THEN 'Customer'
WHEN UPPER(st.sql_text) LIKE '%ACCOUNT_INFO%' THEN 'Account'
WHEN UPPER(st.sql_text) LIKE '%TRANSACTION_LOG%' THEN 'Transaction'
WHEN UPPER(st.sql_text) LIKE '%LOAN%' THEN 'Loan'
ELSE 'Other'
END as business_module,
st.sql_text
FROM v$sql s
JOIN v$sqltext st ON s.sql_id = st.sql_id AND st.piece = 0
WHERE s.executions > 10
AND s.elapsed_time > 10000000 -- 超过10秒的SQL
ORDER BY s.elapsed_time DESC;
3. 锁和阻塞监控
-- 锁等待监控视图
CREATE OR REPLACE VIEW v_lock_waits AS
SELECT
sw.sid as waiting_session,
sw.serial# as waiting_serial,
sw.username as waiting_user,
sw.program as waiting_program,
bw.sid as blocking_session,
bw.serial# as blocking_serial,
bw.username as blocking_user,
bw.program as blocking_program,
lo.object_name as locked_object,
w.event as wait_event,
w.seconds_in_wait,
l1.type as lock_type,
DECODE(l1.lmode,
0, 'None',
1, 'Null',
2, 'Row-S',
3, 'Row-X',
4, 'Share',
5, 'S/Row-X',
6, 'Exclusive'
) as lock_mode_held,
DECODE(l1.request,
0, 'None',
1, 'Null',
2, 'Row-S',
3, 'Row-X',
4, 'Share',
5, 'S/Row-X',
6, 'Exclusive'
) as lock_mode_requested
FROM
v$session sw,
v$session bw,
v$lock l1,
v$lock l2,
v$session_wait w,
(SELECT object_id, object_name FROM dba_objects) lo
WHERE
sw.sid = w.sid
AND l1.sid = sw.sid
AND l2.sid = bw.sid
AND l1.id1 = l2.id1
AND l1.id2 = l2.id2
AND l1.type = l2.type
AND l1.request > 0
AND l2.lmode > 0
AND l1.id1 = lo.object_id (+)
ORDER BY w.seconds_in_wait DESC;
-- 长时间运行的事务监控
CREATE OR REPLACE VIEW v_long_transactions AS
SELECT
s.sid,
s.serial#,
s.username,
s.program,
s.machine,
s.osuser,
ROUND((SYSDATE - s.logon_time) * 24 * 60, 2) as session_minutes,
t.start_time,
ROUND((SYSDATE - t.start_date) * 24 * 60, 2) as transaction_minutes,
t.used_ublk * 8192 / 1024 / 1024 as undo_mb,
s.last_call_et as seconds_since_last_call
FROM
v$session s,
v$transaction t
WHERE
s.taddr = t.addr
AND (SYSDATE - t.start_date) * 24 * 60 > 30 -- 超过30分钟的事务
ORDER BY transaction_minutes DESC;
性能监控自动化
1. 性能数据收集包
-- 性能监控数据收集包
CREATE OR REPLACE PACKAGE pkg_performance_monitor AS
-- 收集实例性能快照
PROCEDURE collect_instance_snapshot;
-- 收集SQL性能统计
PROCEDURE collect_sql_statistics;
-- 收集等待事件统计
PROCEDURE collect_wait_events;
-- 收集锁等待信息
PROCEDURE collect_lock_waits;
-- 生成性能报告
PROCEDURE generate_performance_report(
p_start_time IN DATE,
p_end_time IN DATE
);
-- 性能告警检查
PROCEDURE check_performance_alerts;
END pkg_performance_monitor;
/
CREATE OR REPLACE PACKAGE BODY pkg_performance_monitor AS
-- 收集实例性能快照
PROCEDURE collect_instance_snapshot AS
v_snapshot_id NUMBER;
BEGIN
-- 生成快照ID
SELECT perf_snapshot_seq.NEXTVAL INTO v_snapshot_id FROM dual;
-- 收集实例统计信息
INSERT INTO perf_instance_stats (
snapshot_id, snapshot_time, metric_name, metric_value
)
SELECT
v_snapshot_id,
SYSDATE,
name,
value
FROM v$sysstat
WHERE value > 0;
-- 收集内存使用信息
INSERT INTO perf_memory_stats (
snapshot_id, snapshot_time, memory_type, size_mb
)
SELECT
v_snapshot_id,
SYSDATE,
memory_type,
size_mb
FROM v_memory_usage;
-- 收集会话统计
INSERT INTO perf_session_stats (
snapshot_id, snapshot_time, total_sessions,
active_sessions, waiting_sessions, blocked_sessions
)
SELECT
v_snapshot_id,
SYSDATE,
COUNT(*),
COUNT(CASE WHEN status = 'ACTIVE' THEN 1 END),
COUNT(CASE WHEN wait_class != 'Idle' THEN 1 END),
COUNT(CASE WHEN blocking_session IS NOT NULL THEN 1 END)
FROM v$session;
COMMIT;
DBMS_OUTPUT.PUT_LINE('实例性能快照收集完成,快照ID: ' || v_snapshot_id);
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END collect_instance_snapshot;
-- 收集SQL性能统计
PROCEDURE collect_sql_statistics AS
v_snapshot_id NUMBER;
BEGIN
SELECT perf_snapshot_seq.NEXTVAL INTO v_snapshot_id FROM dual;
-- 采集满足条件的SQL统计,最多100行,未保证按耗时排名
INSERT INTO perf_sql_stats (
snapshot_id, snapshot_time, sql_id, plan_hash_value,
executions, elapsed_time, cpu_time, buffer_gets,
disk_reads, rows_processed
)
SELECT
v_snapshot_id,
SYSDATE,
sql_id,
plan_hash_value,
executions,
elapsed_time,
cpu_time,
buffer_gets,
disk_reads,
rows_processed
FROM v$sql
WHERE executions > 0
AND elapsed_time > 100000 -- 超过0.1秒的SQL
AND ROWNUM <= 100; -- 最多采集100行,未按耗时排序,不代表TOP 100
COMMIT;
DBMS_OUTPUT.PUT_LINE('SQL性能统计收集完成,快照ID: ' || v_snapshot_id);
END collect_sql_statistics;
-- 收集等待事件统计
PROCEDURE collect_wait_events AS
v_snapshot_id NUMBER;
BEGIN
SELECT perf_snapshot_seq.NEXTVAL INTO v_snapshot_id FROM dual;
INSERT INTO perf_wait_events (
snapshot_id, snapshot_time, event_name,
total_waits, time_waited, avg_wait_time
)
SELECT
v_snapshot_id,
SYSDATE,
event,
total_waits,
time_waited,
ROUND(time_waited / NULLIF(total_waits, 0), 2)
FROM v$system_event
WHERE time_waited > 0
AND event NOT LIKE '%message%'
AND event NOT LIKE '%timer%';
COMMIT;
END collect_wait_events;
-- 收集锁等待信息
PROCEDURE collect_lock_waits AS
BEGIN
-- 记录当前的锁等待情况
INSERT INTO perf_lock_waits (
lock_wait_id, snapshot_time, waiting_session, blocking_session,
locked_object, wait_event, seconds_in_wait, lock_type
)
SELECT
lock_wait_seq.NEXTVAL, SYSDATE,
waiting_session,
blocking_session,
locked_object,
wait_event,
seconds_in_wait,
lock_type
FROM v_lock_waits
WHERE seconds_in_wait > 10; -- 只记录等待超过10秒的
COMMIT;
END collect_lock_waits;
-- 生成性能报告
PROCEDURE generate_performance_report(
p_start_time IN DATE,
p_end_time IN DATE
) AS
v_report CLOB;
v_avg_cpu NUMBER;
v_avg_memory NUMBER;
v_top_wait_event VARCHAR2(100);
v_sql_count NUMBER;
BEGIN
v_report := 'Oracle性能分析报告' || CHR(10) ||
'报告期间: ' || TO_CHAR(p_start_time, 'YYYY-MM-DD HH24:MI:SS') ||
' - ' || TO_CHAR(p_end_time, 'YYYY-MM-DD HH24:MI:SS') || CHR(10) ||
RPAD('=', 60, '=') || CHR(10) || CHR(10);
-- 实例性能汇总
v_report := v_report || '一、实例性能汇总' || CHR(10);
-- 获取平均CPU使用率
SELECT AVG(metric_value)
INTO v_avg_cpu
FROM perf_instance_stats
WHERE metric_name = 'CPU used by this session'
AND snapshot_time BETWEEN p_start_time AND p_end_time;
v_report := v_report || ' 平均CPU使用: ' || ROUND(v_avg_cpu, 2) || CHR(10);
-- 获取平均内存使用
SELECT AVG(size_mb)
INTO v_avg_memory
FROM perf_memory_stats
WHERE memory_type = 'SGA'
AND snapshot_time BETWEEN p_start_time AND p_end_time;
v_report := v_report || ' 平均SGA使用: ' || ROUND(v_avg_memory, 2) || ' MB' || CHR(10);
-- 获取主要等待事件
SELECT event_name
INTO v_top_wait_event
FROM (
SELECT event_name, SUM(time_waited) as total_wait
FROM perf_wait_events
WHERE snapshot_time BETWEEN p_start_time AND p_end_time
GROUP BY event_name
ORDER BY total_wait DESC
)
WHERE ROWNUM = 1;
v_report := v_report || ' 主要等待事件: ' || v_top_wait_event || CHR(10) || CHR(10);
-- SQL性能分析
v_report := v_report || '二、SQL性能分析' || CHR(10);
SELECT COUNT(DISTINCT sql_id)
INTO v_sql_count
FROM perf_sql_stats
WHERE snapshot_time BETWEEN p_start_time AND p_end_time;
v_report := v_report || ' 监控SQL数量: ' || v_sql_count || CHR(10);
-- TOP 5 耗时SQL
v_report := v_report || ' TOP 5 耗时SQL:' || CHR(10);
FOR sql_rec IN (
SELECT sql_id, SUM(elapsed_time) / 1000000 as total_seconds
FROM perf_sql_stats
WHERE snapshot_time BETWEEN p_start_time AND p_end_time
GROUP BY sql_id
ORDER BY total_seconds DESC
FETCH FIRST 5 ROWS ONLY
) LOOP
v_report := v_report || ' ' || sql_rec.sql_id ||
': ' || ROUND(sql_rec.total_seconds, 2) || ' 秒' || CHR(10);
END LOOP;
-- 锁等待分析
v_report := v_report || CHR(10) || '三、锁等待分析' || CHR(10);
FOR lock_rec IN (
SELECT
COUNT(*) as wait_count,
AVG(seconds_in_wait) as avg_wait_time,
locked_object
FROM perf_lock_waits
WHERE snapshot_time BETWEEN p_start_time AND p_end_time
GROUP BY locked_object
ORDER BY wait_count DESC
FETCH FIRST 5 ROWS ONLY
) LOOP
v_report := v_report || ' 对象: ' || NVL(lock_rec.locked_object, 'Unknown') ||
', 等待次数: ' || lock_rec.wait_count ||
', 平均等待: ' || ROUND(lock_rec.avg_wait_time, 2) || ' 秒' || CHR(10);
END LOOP;
-- 输出报告
DBMS_OUTPUT.PUT_LINE(v_report);
-- 保存报告
INSERT INTO perf_reports (
report_id, report_time, start_time, end_time, report_content
) VALUES (
perf_report_seq.NEXTVAL, SYSDATE, p_start_time, p_end_time, v_report
);
COMMIT;
END generate_performance_report;
-- 性能告警检查
PROCEDURE check_performance_alerts AS
v_alert_count NUMBER := 0;
BEGIN
-- 检查CPU使用率告警
FOR cpu_rec IN (
SELECT metric_value
FROM perf_instance_stats
WHERE metric_name = 'CPU used by this session'
AND snapshot_time >= SYSDATE - 1/24 -- 最近1小时
AND metric_value > 80 -- CPU使用率超过80%
) LOOP
INSERT INTO performance_alerts (
alert_id, alert_time, alert_type, severity,
description, metric_value
) VALUES (
perf_alert_seq.NEXTVAL, SYSDATE, 'HIGH_CPU', 'HIGH',
'CPU使用率过高', cpu_rec.metric_value
);
v_alert_count := v_alert_count + 1;
END LOOP;
-- 检查累计耗时较高的SQL游标,不判断当前执行时长
FOR sql_rec IN (
SELECT sql_id, elapsed_time / 1000000 as elapsed_seconds
FROM v$sql
WHERE elapsed_time / 1000000 > 300 -- 游标累计耗时超过300秒,不代表当前单次执行超过5分钟
AND executions > 0
) LOOP
INSERT INTO performance_alerts (
alert_id, alert_time, alert_type, severity,
description, metric_value, sql_id
) VALUES (
perf_alert_seq.NEXTVAL, SYSDATE, 'HIGH_CUMULATIVE_SQL_TIME', 'MEDIUM',
'SQL游标累计耗时超过阈值,不代表当前执行超时', sql_rec.elapsed_seconds, sql_rec.sql_id
);
v_alert_count := v_alert_count + 1;
END LOOP;
-- 检查锁等待告警
FOR lock_rec IN (
SELECT waiting_session, seconds_in_wait
FROM v_lock_waits
WHERE seconds_in_wait > 60 -- 等待超过1分钟
) LOOP
INSERT INTO performance_alerts (
alert_id, alert_time, alert_type, severity,
description, metric_value, session_id
) VALUES (
perf_alert_seq.NEXTVAL, SYSDATE, 'LOCK_WAIT', 'HIGH',
'锁等待时间过长', lock_rec.seconds_in_wait, lock_rec.waiting_session
);
v_alert_count := v_alert_count + 1;
END LOOP;
COMMIT;
IF v_alert_count > 0 THEN
DBMS_OUTPUT.PUT_LINE('性能检查完成,发现 ' || v_alert_count || ' 个告警');
ELSE
DBMS_OUTPUT.PUT_LINE('性能检查完成,无告警');
END IF;
END check_performance_alerts;
END pkg_performance_monitor;
/
2. 性能数据存储表
-- 创建性能监控相关表
CREATE TABLE perf_instance_stats (
snapshot_id NUMBER,
snapshot_time DATE,
metric_name VARCHAR2(100),
metric_value NUMBER,
PRIMARY KEY (snapshot_id, metric_name)
);
CREATE TABLE perf_memory_stats (
snapshot_id NUMBER,
snapshot_time DATE,
memory_type VARCHAR2(50),
size_mb NUMBER(10,2),
PRIMARY KEY (snapshot_id, memory_type)
);
CREATE TABLE perf_session_stats (
snapshot_id NUMBER PRIMARY KEY,
snapshot_time DATE,
total_sessions NUMBER,
active_sessions NUMBER,
waiting_sessions NUMBER,
blocked_sessions NUMBER
);
CREATE TABLE perf_sql_stats (
snapshot_id NUMBER,
snapshot_time DATE,
sql_id VARCHAR2(13),
plan_hash_value NUMBER,
executions NUMBER,
elapsed_time NUMBER,
cpu_time NUMBER,
buffer_gets NUMBER,
disk_reads NUMBER,
rows_processed NUMBER,
PRIMARY KEY (snapshot_id, sql_id, plan_hash_value)
);
CREATE TABLE perf_wait_events (
snapshot_id NUMBER,
snapshot_time DATE,
event_name VARCHAR2(100),
total_waits NUMBER,
time_waited NUMBER,
avg_wait_time NUMBER(10,2),
PRIMARY KEY (snapshot_id, event_name)
);
CREATE TABLE perf_lock_waits (
lock_wait_id NUMBER PRIMARY KEY,
snapshot_time DATE,
waiting_session NUMBER,
blocking_session NUMBER,
locked_object VARCHAR2(100),
wait_event VARCHAR2(100),
seconds_in_wait NUMBER,
lock_type VARCHAR2(20)
);
CREATE TABLE performance_alerts (
alert_id NUMBER PRIMARY KEY,
alert_time DATE,
alert_type VARCHAR2(50),
severity VARCHAR2(20),
description VARCHAR2(500),
metric_value NUMBER,
sql_id VARCHAR2(13),
session_id NUMBER,
acknowledged CHAR(1) DEFAULT 'N'
);
CREATE TABLE perf_reports (
report_id NUMBER PRIMARY KEY,
report_time DATE,
start_time DATE,
end_time DATE,
report_content CLOB
);
-- 创建序列
CREATE SEQUENCE perf_snapshot_seq START WITH 1 INCREMENT BY 1;
CREATE SEQUENCE perf_alert_seq START WITH 1 INCREMENT BY 1;
CREATE SEQUENCE perf_report_seq START WITH 1 INCREMENT BY 1;
CREATE SEQUENCE lock_wait_seq START WITH 1 INCREMENT BY 1;
银行业务性能监控
1. 业务响应时间监控
-- 银行业务响应时间监控
CREATE OR REPLACE VIEW v_banking_response_time AS
SELECT
'Customer Query' as business_function,
AVG(elapsed_time / executions / 1000000) as avg_response_seconds,
COUNT(*) as sql_count,
SUM(executions) as total_executions
FROM v$sql
WHERE UPPER(sql_text) LIKE '%CUSTOMER_INFO%'
AND UPPER(sql_text) LIKE '%SELECT%'
AND executions > 0
UNION ALL
SELECT
'Account Balance',
AVG(elapsed_time / executions / 1000000),
COUNT(*),
SUM(executions)
FROM v$sql
WHERE UPPER(sql_text) LIKE '%ACCOUNT_INFO%'
AND UPPER(sql_text) LIKE '%BALANCE%'
AND executions > 0
UNION ALL
SELECT
'Transaction Processing',
AVG(elapsed_time / executions / 1000000),
COUNT(*),
SUM(executions)
FROM v$sql
WHERE UPPER(sql_text) LIKE '%TRANSACTION_LOG%'
AND UPPER(sql_text) LIKE '%INSERT%'
AND executions > 0
UNION ALL
SELECT
'Loan Application',
AVG(elapsed_time / executions / 1000000),
COUNT(*),
SUM(executions)
FROM v$sql
WHERE UPPER(sql_text) LIKE '%LOAN%'
AND executions > 0;
-- 银行核心交易TPS监控
CREATE OR REPLACE FUNCTION get_banking_tps(p_minutes NUMBER DEFAULT 5)
RETURN NUMBER AS
v_transaction_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_transaction_count
FROM transaction_log
WHERE trans_time >= SYSDATE - p_minutes / (24 * 60)
AND status = 'SUCCESS';
RETURN ROUND(v_transaction_count / (p_minutes * 60), 2); -- 转换为每秒,p_minutes须大于0
END get_banking_tps;
/
2. 资源使用分析
-- 数据库连接池监控
CREATE OR REPLACE VIEW v_connection_pool_status AS
SELECT
machine,
program,
COUNT(*) as connection_count,
COUNT(CASE WHEN status = 'ACTIVE' THEN 1 END) as active_connections,
COUNT(CASE WHEN status = 'INACTIVE' THEN 1 END) as idle_connections,
AVG(SYSDATE - logon_time) * 24 as avg_session_hours
FROM v$session
WHERE type = 'USER'
GROUP BY machine, program
ORDER BY connection_count DESC;
-- 表空间增长趋势分析
CREATE OR REPLACE PROCEDURE analyze_tablespace_growth AS
CURSOR c_tablespaces IS
SELECT tablespace_name FROM dba_tablespaces
WHERE contents = 'PERMANENT';
v_current_size NUMBER;
v_used_size NUMBER;
v_growth_rate NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('表空间增长趋势分析:');
DBMS_OUTPUT.PUT_LINE(RPAD('表空间名称', 20) || RPAD('当前大小(MB)', 15) ||
RPAD('已用大小(MB)', 15) || '假设增长量(MB/天,按已用量1%)');
DBMS_OUTPUT.PUT_LINE(RPAD('-', 65, '-'));
FOR ts_rec IN c_tablespaces LOOP
-- 获取当前表空间大小
SELECT NVL(SUM(bytes) / 1024 / 1024, 0)
INTO v_current_size
FROM dba_data_files
WHERE tablespace_name = ts_rec.tablespace_name;
-- 获取已使用大小
SELECT v_current_size - NVL(SUM(bytes) / 1024 / 1024, 0)
INTO v_used_size
FROM dba_free_space
WHERE tablespace_name = ts_rec.tablespace_name;
-- 计算增长率(简化计算,实际应基于历史数据)
v_growth_rate := v_used_size * 0.01; -- 假设每天增长1%
DBMS_OUTPUT.PUT_LINE(
RPAD(ts_rec.tablespace_name, 20) ||
RPAD(TO_CHAR(v_current_size, '999,999.99'), 15) ||
RPAD(TO_CHAR(v_used_size, '999,999.99'), 15) ||
TO_CHAR(v_growth_rate, '999.99')
);
END LOOP;
END analyze_tablespace_growth;
/
性能诊断工具
1. SQL性能诊断
-- SQL性能诊断包
CREATE OR REPLACE PACKAGE pkg_sql_diagnosis AS
PROCEDURE analyze_sql_performance(p_sql_id VARCHAR2);
PROCEDURE compare_execution_plans(p_sql_id VARCHAR2);
PROCEDURE identify_resource_intensive_sql;
FUNCTION get_sql_recommendations(p_sql_id VARCHAR2) RETURN CLOB;
END pkg_sql_diagnosis;
/
CREATE OR REPLACE PACKAGE BODY pkg_sql_diagnosis AS
PROCEDURE analyze_sql_performance(p_sql_id VARCHAR2) AS
v_sql_text CLOB;
v_executions NUMBER;
v_avg_elapsed NUMBER;
v_avg_cpu NUMBER;
v_avg_io NUMBER;
v_buffer_gets NUMBER;
v_disk_reads NUMBER;
BEGIN
-- 获取SQL基本信息
SELECT
sql_fulltext,
executions,
elapsed_time / executions / 1000000,
cpu_time / executions / 1000000,
user_io_wait_time / executions / 1000000,
buffer_gets / executions,
disk_reads / executions
INTO
v_sql_text,
v_executions,
v_avg_elapsed,
v_avg_cpu,
v_avg_io,
v_buffer_gets,
v_disk_reads
FROM v$sql
WHERE sql_id = p_sql_id
AND ROWNUM = 1;
DBMS_OUTPUT.PUT_LINE('SQL性能分析报告');
DBMS_OUTPUT.PUT_LINE('SQL ID: ' || p_sql_id);
DBMS_OUTPUT.PUT_LINE(RPAD('=', 50, '='));
DBMS_OUTPUT.PUT_LINE('执行次数: ' || v_executions);
DBMS_OUTPUT.PUT_LINE('平均执行时间: ' || ROUND(v_avg_elapsed, 3) || ' 秒');
DBMS_OUTPUT.PUT_LINE('平均CPU时间: ' || ROUND(v_avg_cpu, 3) || ' 秒');
DBMS_OUTPUT.PUT_LINE('平均IO等待: ' || ROUND(v_avg_io, 3) || ' 秒');
DBMS_OUTPUT.PUT_LINE('平均逻辑读: ' || ROUND(v_buffer_gets));
DBMS_OUTPUT.PUT_LINE('平均物理读: ' || ROUND(v_disk_reads));
-- 性能评估
IF v_avg_elapsed > 5 THEN
DBMS_OUTPUT.PUT_LINE('⚠ 警告: 平均执行时间较长');
END IF;
IF v_buffer_gets > 10000 THEN
DBMS_OUTPUT.PUT_LINE('⚠ 警告: 逻辑读次数过多');
END IF;
IF v_disk_reads > 1000 THEN
DBMS_OUTPUT.PUT_LINE('⚠ 警告: 物理读次数过多,考虑优化索引');
END IF;
DBMS_OUTPUT.PUT_LINE(CHR(10) || 'SQL文本:');
DBMS_OUTPUT.PUT_LINE(SUBSTR(v_sql_text, 1, 1000));
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('错误: SQL ID ' || p_sql_id || ' 不存在');
END analyze_sql_performance;
PROCEDURE compare_execution_plans(p_sql_id VARCHAR2) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('SQL执行计划对比: ' || p_sql_id);
DBMS_OUTPUT.PUT_LINE(RPAD('=', 50, '='));
FOR plan_rec IN (
SELECT
plan_hash_value,
executions,
ROUND(elapsed_time / executions / 1000000, 3) as avg_elapsed,
buffer_gets / executions as avg_buffer_gets,
disk_reads / executions as avg_disk_reads
FROM v$sql
WHERE sql_id = p_sql_id
ORDER BY executions DESC
) LOOP
DBMS_OUTPUT.PUT_LINE('计划哈希值: ' || plan_rec.plan_hash_value);
DBMS_OUTPUT.PUT_LINE(' 执行次数: ' || plan_rec.executions);
DBMS_OUTPUT.PUT_LINE(' 平均执行时间: ' || plan_rec.avg_elapsed || ' 秒');
DBMS_OUTPUT.PUT_LINE(' 平均逻辑读: ' || ROUND(plan_rec.avg_buffer_gets));
DBMS_OUTPUT.PUT_LINE(' 平均物理读: ' || ROUND(plan_rec.avg_disk_reads));
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
END compare_execution_plans;
PROCEDURE identify_resource_intensive_sql AS
BEGIN
DBMS_OUTPUT.PUT_LINE('资源密集型SQL识别');
DBMS_OUTPUT.PUT_LINE(RPAD('=', 80, '='));
DBMS_OUTPUT.PUT_LINE(RPAD('SQL_ID', 15) || RPAD('执行次数', 10) ||
RPAD('总耗时(秒)', 12) || RPAD('平均耗时(秒)', 12) || '资源类型');
DBMS_OUTPUT.PUT_LINE(RPAD('-', 80, '-'));
-- CPU密集型SQL
FOR cpu_rec IN (
SELECT sql_id, executions,
ROUND(cpu_time / 1000000, 2) as total_cpu,
ROUND(cpu_time / executions / 1000000, 3) as avg_cpu
FROM v$sql
WHERE executions > 10
AND cpu_time > 60000000 -- 总CPU时间超过60秒
ORDER BY cpu_time DESC
FETCH FIRST 5 ROWS ONLY
) LOOP
DBMS_OUTPUT.PUT_LINE(
RPAD(cpu_rec.sql_id, 15) ||
RPAD(cpu_rec.executions, 10) ||
RPAD(cpu_rec.total_cpu, 12) ||
RPAD(cpu_rec.avg_cpu, 12) ||
'CPU密集型'
);
END LOOP;
-- IO密集型SQL
FOR io_rec IN (
SELECT sql_id, executions,
ROUND(user_io_wait_time / 1000000, 2) as total_io,
ROUND(user_io_wait_time / executions / 1000000, 3) as avg_io
FROM v$sql
WHERE executions > 10
AND user_io_wait_time > 60000000 -- 总IO等待超过60秒
ORDER BY user_io_wait_time DESC
FETCH FIRST 5 ROWS ONLY
) LOOP
DBMS_OUTPUT.PUT_LINE(
RPAD(io_rec.sql_id, 15) ||
RPAD(io_rec.executions, 10) ||
RPAD(io_rec.total_io, 12) ||
RPAD(io_rec.avg_io, 12) ||
'IO密集型'
);
END LOOP;
END identify_resource_intensive_sql;
FUNCTION get_sql_recommendations(p_sql_id VARCHAR2) RETURN CLOB AS
v_recommendations CLOB;
v_sql_text CLOB;
v_buffer_gets NUMBER;
v_disk_reads NUMBER;
v_executions NUMBER;
BEGIN
-- 获取SQL统计信息
SELECT sql_fulltext, buffer_gets, disk_reads, executions
INTO v_sql_text, v_buffer_gets, v_disk_reads, v_executions
FROM v$sql
WHERE sql_id = p_sql_id AND ROWNUM = 1;
v_recommendations := 'SQL优化建议 (' || p_sql_id || ')' || CHR(10) || CHR(10);
-- 基于统计信息给出建议
IF v_disk_reads / v_executions > 1000 THEN
v_recommendations := v_recommendations ||
'• 物理读次数过多,建议检查和优化索引' || CHR(10);
END IF;
IF v_buffer_gets / v_executions > 10000 THEN
v_recommendations := v_recommendations ||
'• 逻辑读次数过多,考虑重写SQL或优化表结构' || CHR(10);
END IF;
-- 基于SQL文本给出建议
IF UPPER(v_sql_text) LIKE '%SELECT%*%FROM%' THEN
v_recommendations := v_recommendations ||
'• 避免使用SELECT *,只选择需要的列' || CHR(10);
END IF;
IF UPPER(v_sql_text) LIKE '%ORDER BY%' AND
UPPER(v_sql_text) NOT LIKE '%INDEX%' THEN
v_recommendations := v_recommendations ||
'• ORDER BY操作可能导致排序,考虑创建相应索引' || CHR(10);
END IF;
IF UPPER(v_sql_text) LIKE '%GROUP BY%' THEN
v_recommendations := v_recommendations ||
'• GROUP BY操作,确保分组列上有合适的索引' || CHR(10);
END IF;
IF UPPER(v_sql_text) LIKE '%LIKE ''%' THEN
v_recommendations := v_recommendations ||
'• 文本规则命中LIKE片段,但不能确认存在前导通配符;若确为前导通配符查询,普通B-tree索引通常难以进行有效范围扫描,应结合执行计划、索引类型和业务需求评估优化方案' || CHR(10);
END IF;
RETURN v_recommendations;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'SQL ID ' || p_sql_id || ' 不存在或已从内存中清除';
END get_sql_recommendations;
END pkg_sql_diagnosis;
/
2. 定时监控作业
-- 创建性能监控定时作业
BEGIN
-- 每5分钟收集一次实例快照
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'PERF_INSTANCE_MONITOR',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN pkg_performance_monitor.collect_instance_snapshot; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY; INTERVAL=5',
enabled => TRUE,
comments => '每5分钟收集实例性能快照'
);
-- 每小时收集SQL统计
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'PERF_SQL_MONITOR',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN pkg_performance_monitor.collect_sql_statistics; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=HOURLY; INTERVAL=1',
enabled => TRUE,
comments => '每小时收集SQL性能统计'
);
-- 每10分钟检查性能告警
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'PERF_ALERT_CHECK',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN pkg_performance_monitor.check_performance_alerts; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY; INTERVAL=10',
enabled => TRUE,
comments => '每10分钟检查性能告警'
);
-- 每日生成性能报告
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'PERF_DAILY_REPORT',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN pkg_performance_monitor.generate_performance_report(SYSDATE-1, SYSDATE); END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=6; BYMINUTE=0',
enabled => TRUE,
comments => '每日早上6点生成性能报告'
);
END;
/
本文示例展示了Oracle性能采集、预警和诊断的组织方式;在修正代码与统计口径、补足业务表和部署前置并验证采样策略后,可辅助银行数据库的周期性监控与问题定位,但不能保证核心业务系统稳定高效运行。