yashanb教程FG195-YashanDB大事务拆分
本文档风哥主要介绍YashanDB大事务拆分相关知识,包括YashanDB大事务的概念、影响、原因、拆分规划、拆分方法、实现、监控、故障排查、生产案例与实战讲解等内容,风哥教程参考YashanDB官方文档性能调优内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 YashanDB大事务的概念
YashanDB大事务是指操作数据量大、执行时间长的事务,通常是指处理大量数据的事务,如批量更新、删除或插入操作。大事务可能会占用数据库资源,影响其他事务的执行,甚至导致数据库性能下降。更多视频教程www.fgedu.net.cn
- 大事务是指操作数据量大的事务
- 大事务的判断标准通常根据操作的数据量和执行时间来确定
- 大事务可能会占用大量的数据库资源,如锁、内存、undo空间等
- 大事务可能导致锁等待、死锁、回滚开销大等问题
1.2 YashanDB大事务的影响
YashanDB大事务的影响包括:
- 锁竞争:大事务会持有锁的时间较长,导致其他事务等待
- 资源占用:大事务会占用大量的数据库资源,如内存、undo空间等
- 性能下降:大事务会导致数据库性能下降,影响整体系统性能
- 回滚开销:大事务的回滚会消耗大量资源和时间
- 日志增长:大事务会产生大量的 redo 日志,导致日志文件增长过快
- 备份影响:大事务会影响数据库备份的执行
- 系统稳定性:大事务可能导致系统不稳定,甚至崩溃
1.3 YashanDB大事务的原因
YashanDB大事务的常见原因包括:
- 批量操作:处理大量数据的批量更新、删除或插入操作
- 复杂查询:执行复杂的查询,如多表关联、聚合操作等
- 事务范围过大:事务包含了过多的操作,导致事务范围过大
- 数据量增长:随着业务的发展,数据量不断增长,导致原本的小事务变成大事务
- 应用程序设计不合理:应用程序设计时没有考虑事务的大小,导致大事务的产生
Part02-生产环境规划与建议
2.1 YashanDB大事务拆分规划
YashanDB大事务拆分规划建议:
– 数据量原则:根据操作的数据量大小,将大事务拆分为多个小事务
– 时间原则:根据事务的执行时间,将大事务拆分为多个小事务
– 业务逻辑原则:根据业务逻辑的独立性,将大事务拆分为多个小事务
– 资源原则:根据系统资源的使用情况,合理拆分大事务
– 可管理性原则:拆分后的事务应便于管理和监控
# 大事务拆分流程
1. 分析大事务:分析大事务的内容、数据量、执行时间等
2. 确定拆分策略:根据大事务的特点,确定合适的拆分策略
3. 设计拆分方案:设计具体的拆分方案,包括拆分点、拆分方法等
4. 实施拆分:按照拆分方案实施大事务拆分
5. 验证效果:验证拆分后的效果,确保系统性能得到改善
6. 持续优化:根据实际情况,持续优化拆分方案
# 大事务拆分策略
– 按数据量拆分:将大量数据拆分为多个小批次处理
– 按时间拆分:将长时间运行的事务拆分为多个短时间运行的事务
– 按业务逻辑拆分:将复杂的业务逻辑拆分为多个独立的业务逻辑
– 按表拆分:将涉及多个表的事务拆分为多个单表事务
– 按分区拆分:利用表分区,将大事务拆分为多个分区事务
2.2 YashanDB大事务拆分方法
YashanDB大事务拆分方法:
# 1. 批量处理法
– 适用场景:处理大量数据的批量更新、删除或插入操作
– 方法:将大量数据拆分为多个小批次处理,每批次处理一部分数据,然后提交事务
– 优点:减少事务的大小,降低资源占用,提高系统稳定性
– 缺点:需要编写额外的代码来实现批量处理
# 2. 分段处理法
– 适用场景:处理大量数据的操作,如数据迁移、数据清理等
– 方法:将数据按照某种规则(如ID范围、时间范围等)分段,每段数据作为一个事务处理
– 优点:可以并行处理不同段的数据,提高处理效率
– 缺点:需要确定合适的分段规则,确保数据的完整性
# 3. 业务逻辑拆分法
– 适用场景:业务逻辑复杂的大事务
– 方法:将复杂的业务逻辑拆分为多个独立的业务逻辑,每个业务逻辑作为一个事务处理
– 优点:提高业务逻辑的可读性和可维护性,减少事务的大小
– 缺点:需要确保业务逻辑的一致性
# 4. 表拆分法
– 适用场景:涉及多个表的大事务
– 方法:将涉及多个表的事务拆分为多个单表事务,每个单表事务处理一个表的数据
– 优点:减少事务的复杂度,提高事务的执行效率
– 缺点:需要确保表之间的数据一致性
# 5. 分区处理法
– 适用场景:处理分区表的大事务
– 方法:利用表分区,将大事务拆分为多个分区事务,每个分区事务处理一个分区的数据
– 优点:减少事务的大小,提高处理效率
– 缺点:需要表已经进行了分区
2.3 YashanDB大事务拆分最佳实践
YashanDB大事务拆分最佳实践:
# 1. 批量处理最佳实践
– 确定合适的批量大小:根据系统资源和数据量,确定合适的批量大小
– 使用游标或循环:使用游标或循环来处理批量数据
– 及时提交:每处理完一个批量,及时提交事务
– 错误处理:添加错误处理机制,确保批量处理的可靠性
– 监控和日志:添加监控和日志,便于调试和问题排查
# 2. 分段处理最佳实践
– 选择合适的分段字段:选择合适的字段(如ID、时间等)作为分段依据
– 确定合适的分段大小:根据系统资源和数据量,确定合适的分段大小
– 并行处理:利用并行处理技术,提高处理效率
– 数据验证:处理完成后,验证数据的完整性
– 回滚机制:建立回滚机制,确保在出现错误时能够回滚
# 3. 业务逻辑拆分最佳实践
– 识别独立的业务逻辑:识别可以独立处理的业务逻辑
– 确定事务边界:明确每个事务的边界,确保业务逻辑的完整性
– 消息队列:使用消息队列来协调不同业务逻辑之间的处理
– 事务补偿:建立事务补偿机制,确保在出现错误时能够补偿
– 监控和告警:添加监控和告警,及时发现和处理问题
# 4. 表拆分最佳实践
– 识别相关表:识别事务中涉及的相关表
– 确定处理顺序:确定表的处理顺序,确保数据的一致性
– 外键处理:处理好表之间的外键关系
– 批量处理:对每个表使用批量处理技术
– 数据验证:处理完成后,验证表之间的数据一致性
# 5. 分区处理最佳实践
– 合理设计分区:根据业务需求,合理设计表分区
– 利用分区剪枝:利用分区剪枝技术,提高查询效率
– 分区级事务:使用分区级事务,减少事务的大小
– 并行处理:对不同分区并行处理,提高处理效率
– 分区维护:定期维护分区,确保分区的有效性
Part03-生产环境项目实施方案
3.1 YashanDB大事务拆分实现
3.1.1 批量处理法实现
# 1. 批量更新实现
SQL> BEGIN
2 FOR i IN 1..10 LOOP
3 UPDATE fgedu.orders
4 SET status = ‘COMPLETED’
5 WHERE order_date < SYSDATE - 30
6 AND rownum <= 10000;
7 COMMIT;
8 EXIT WHEN SQL%ROWCOUNT = 0;
9 END LOOP;
10 END;
11 /
PL/SQL procedure successfully completed.
# 2. 批量删除实现
SQL> BEGIN
2 FOR i IN 1..10 LOOP
3 DELETE FROM fgedu.order_history
4 WHERE order_date < SYSDATE - 365
5 AND rownum <= 10000;
6 COMMIT;
7 EXIT WHEN SQL%ROWCOUNT = 0;
8 END LOOP;
9 END;
10 /
PL/SQL procedure successfully completed.
# 3. 批量插入实现
SQL> BEGIN
2 FOR i IN 1..10 LOOP
3 INSERT INTO fgedu.order_items
4 SELECT * FROM fgedu.temp_order_items
5 WHERE rownum <= 100000;
6 COMMIT;
7 DELETE FROM fgedu.temp_order_items WHERE rownum <= 100000;
8 COMMIT;
9 EXIT WHEN SQL%ROWCOUNT = 0;
10 END LOOP;
11 END;
12 /
PL/SQL procedure successfully completed.
# 4. 批量处理脚本
#!/bin/bash
# batch_process.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: `http://www.fgedu.net.cn`
# 批量处理脚本
batch_size=10000
start_id=1
end_id=100000
while [ $start_id -le $end_id ]; do
current_end=$((start_id + batch_size - 1))
if [ $current_end -gt $end_id ]; then
current_end=$end_id
fi
sqlplus -s / as sysdba << EOF
UPDATE fgedu.orders
SET status = 'COMPLETED'
WHERE order_id BETWEEN $start_id AND $current_end;
COMMIT;
EOF
echo "Processed orders from $start_id to $current_end"
start_id=$((current_end + 1))
done
echo "Batch processing completed"
3.1.2 分段处理法实现
# 1. 按ID范围分段处理
SQL> DECLARE
2 v_start_id NUMBER := 1;
3 v_end_id NUMBER := 100000;
4 v_batch_size NUMBER := 10000;
5 v_current_start NUMBER;
6 v_current_end NUMBER;
7 BEGIN
8 v_current_start := v_start_id;
9 WHILE v_current_start <= v_end_id LOOP
10 v_current_end := v_current_start + v_batch_size - 1;
11 IF v_current_end > v_end_id THEN
12 v_current_end := v_end_id;
13 END IF;
14
15 UPDATE fgedu.orders
16 SET status = ‘COMPLETED’
17 WHERE order_id BETWEEN v_current_start AND v_current_end;
18 COMMIT;
19
20 DBMS_OUTPUT.PUT_LINE(‘Processed orders from ‘ || v_current_start || ‘ to ‘ || v_current_end);
21 v_current_start := v_current_end + 1;
22 END LOOP;
23 END;
24 /
PL/SQL procedure successfully completed.
# 2. 按时间范围分段处理
SQL> DECLARE
2 v_start_date DATE := SYSDATE – 365;
3 v_end_date DATE := SYSDATE;
4 v_interval NUMBER := 30; — 30天为一个分段
5 v_current_start DATE;
6 v_current_end DATE;
7 BEGIN
8 v_current_start := v_start_date;
9 WHILE v_current_start < v_end_date LOOP
10 v_current_end := v_current_start + v_interval;
11 IF v_current_end > v_end_date THEN
12 v_current_end := v_end_date;
13 END IF;
14
15 UPDATE fgedu.orders
16 SET status = ‘COMPLETED’
17 WHERE order_date BETWEEN v_current_start AND v_current_end;
18 COMMIT;
19
20 DBMS_OUTPUT.PUT_LINE(‘Processed orders from ‘ || v_current_start || ‘ to ‘ || v_current_end);
21 v_current_start := v_current_end;
22 END LOOP;
23 END;
24 /
PL/SQL procedure successfully completed.
# 3. 并行分段处理
SQL> DECLARE
2 TYPE id_range IS RECORD (
3 start_id NUMBER,
4 end_id NUMBER
5 );
6 TYPE id_range_tab IS TABLE OF id_range;
7 v_ranges id_range_tab := id_range_tab();
8 BEGIN
9 — 定义分段
10 v_ranges.extend(5);
11 v_ranges(1).start_id := 1;
12 v_ranges(1).end_id := 20000;
13 v_ranges(2).start_id := 20001;
14 v_ranges(2).end_id := 40000;
15 v_ranges(3).start_id := 40001;
16 v_ranges(3).end_id := 60000;
17 v_ranges(4).start_id := 60001;
18 v_ranges(4).end_id := 80000;
19 v_ranges(5).start_id := 80001;
20 v_ranges(5).end_id := 100000;
21
22 — 并行处理每个分段
23 FORALL i IN 1..v_ranges.count
24 UPDATE /*+ PARALLEL(4) */ fgedu.orders
25 SET status = ‘COMPLETED’
26 WHERE order_id BETWEEN v_ranges(i).start_id AND v_ranges(i).end_id;
27 COMMIT;
28 END;
29 /
PL/SQL procedure successfully completed.
3.1.3 业务逻辑拆分法实现
# 1. 原大事务
BEGIN
— 操作1:更新订单状态
UPDATE fgedu.orders SET status = ‘COMPLETED’ WHERE order_id = 123;
— 操作2:更新库存
UPDATE fgedu.inventory SET quantity = quantity – 1 WHERE product_id = 456;
— 操作3:记录交易历史
INSERT INTO fgedu.transaction_history (order_id, product_id, quantity)
VALUES (123, 456, 1);
— 操作4:发送通知
INSERT INTO fgedu.notifications (user_id, message)
VALUES (789, ‘订单已完成’);
COMMIT;
END;
/
# 2. 拆分后的小事务
— 事务1:更新订单状态
BEGIN
UPDATE fgedu.orders SET status = ‘COMPLETED’ WHERE order_id = 123;
COMMIT;
END;
/
— 事务2:更新库存
BEGIN
UPDATE fgedu.inventory SET quantity = quantity – 1 WHERE product_id = 456;
COMMIT;
END;
/
— 事务3:记录交易历史
BEGIN
INSERT INTO fgedu.transaction_history (order_id, product_id, quantity)
VALUES (123, 456, 1);
COMMIT;
END;
/
— 事务4:发送通知
BEGIN
INSERT INTO fgedu.notifications (user_id, message)
VALUES (789, ‘订单已完成’);
COMMIT;
END;
/
# 3. 使用消息队列协调
— 发送消息
BEGIN
DBMS_AQ.ENQUEUE(
queue_name => ‘ORDER_QUEUE’,
enqueue_options => NULL,
message_properties => NULL,
payload => order_message,
msgid => message_id
);
COMMIT;
END;
/
— 接收消息并处理
BEGIN
DBMS_AQ.DEQUEUE(
queue_name => ‘ORDER_QUEUE’,
dequeue_options => dequeue_options,
message_properties => message_properties,
payload => order_message,
msgid => message_id
);
— 处理订单
UPDATE fgedu.orders SET status = ‘COMPLETED’ WHERE order_id = order_message.order_id;
COMMIT;
END;
/
3.2 YashanDB大事务监控
3.2.1 YashanDB大事务监控命令
# 1. 监控当前活跃事务
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
# 2. 监控SQL执行情况
SQL> SELECT sql_id, elapsed_time, buffer_gets, executions,
elapsed_time / executions / 1000000 AS avg_elapsed_seconds,
rows_processed
FROM v$sql
WHERE executions > 0
ORDER BY elapsed_time DESC, rows_processed DESC;
# 3. 监控锁等待
SQL> SELECT l.session_id, l.lock_type, l.mode_held, l.mode_requested,
s.username, s.sql_id, (SYSDATE – s.logon_time) * 24 * 60 AS minutes_active
FROM dba_locks l
JOIN v$session s ON l.session_id = s.sid
WHERE l.blocking_others = ‘Blocking’
ORDER BY minutes_active DESC;
# 4. 监控undo使用情况
SQL> SELECT tablespace_name, file_id, block_id, blocks, status,
(SYSDATE – creation_time) * 24 * 60 AS minutes_old
FROM dba_undo_extents
WHERE status = ‘ACTIVE’
ORDER BY minutes_old DESC;
# 5. 监控redo日志生成
SQL> SELECT * FROM v$log;
SQL> SELECT * FROM v$log_history ORDER BY first_time DESC;
3.2.2 YashanDB大事务监控脚本
# large_transaction_monitor.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: `http://www.fgedu.net.cn`
# 大事务监控脚本
# 输出文件
output_file=”/tmp/large_transaction_monitor_$(date +%Y%m%d_%H%M%S).log”
echo “开始监控大事务” > ${output_file}
echo “监控时间: $(date)” >> ${output_file}
echo “” >> ${output_file}
# 监控当前活跃事务
echo “===== 当前活跃事务 ====” >> ${output_file}
sqlplus -s / as sysdba << EOF >> ${output_file}
SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v\$session s
JOIN v\$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
EXIT;
EOF
echo “” >> ${output_file}
# 监控SQL执行情况
echo “===== SQL执行情况 ====” >> ${output_file}
sqlplus -s / as sysdba << EOF >> ${output_file}
SELECT sql_id, elapsed_time, buffer_gets, executions,
elapsed_time / executions / 1000000 AS avg_elapsed_seconds,
rows_processed
FROM v\$sql
WHERE executions > 0
ORDER BY elapsed_time DESC, rows_processed DESC
FETCH FIRST 10 ROWS ONLY;
EXIT;
EOF
echo “” >> ${output_file}
# 监控锁等待
echo “===== 锁等待 ====” >> ${output_file}
sqlplus -s / as sysdba << EOF >> ${output_file}
SELECT l.session_id, l.lock_type, l.mode_held, l.mode_requested,
s.username, s.sql_id, (SYSDATE – s.logon_time) * 24 * 60 AS minutes_active
FROM dba_locks l
JOIN v\$session s ON l.session_id = s.sid
WHERE l.blocking_others = ‘Blocking’
ORDER BY minutes_active DESC;
EXIT;
EOF
echo “” >> ${output_file}
# 监控undo使用情况
echo “===== undo使用情况 ====” >> ${output_file}
sqlplus -s / as sysdba << EOF >> ${output_file}
SELECT tablespace_name, file_id, block_id, blocks, status,
(SYSDATE – creation_time) * 24 * 60 AS minutes_old
FROM dba_undo_extents
WHERE status = ‘ACTIVE’
ORDER BY minutes_old DESC
FETCH FIRST 10 ROWS ONLY;
EXIT;
EOF
echo “” >> ${output_file}
echo “大事务监控完成,结果保存至:${output_file}” >> ${output_file}
echo “大事务监控完成,结果保存至:${output_file}”
# 检查是否有大事务
large_transaction_count=$(sqlplus -s / as sysdba << EOF
SET HEAD OFF
SET FEEDBACK OFF
SELECT COUNT(*) FROM v\$transaction t WHERE t.used_ublk > 10000;
EXIT;
EOF
)
if [ $large_transaction_count -gt 0 ]; then
echo “发现大事务!数量: $large_transaction_count”
# 发送告警
echo “大事务告警:发现 $large_transaction_count 个大事务” | mail -s “YashanDB大事务告警” admin@fgedu.net.cn
fi
3.3 YashanDB大事务故障排查
3.3.1 YashanDB大事务故障排查步骤
# 1. 发现大事务
– 通过监控系统发现大事务
– 通过告警信息发现大事务
– 通过用户反馈发现大事务
# 2. 分析大事务
– 查看大事务的SQL语句
– 查看大事务的执行计划
– 查看大事务的资源使用情况
– 查看大事务的锁等待情况
– 查看大事务的undo使用情况
# 3. 确定大事务的原因
– 批量操作
– 复杂查询
– 事务范围过大
– 数据量增长
– 应用程序设计不合理
# 4. 采取处理措施
– 终止大事务
– 优化SQL语句
– 拆分大事务
– 增加系统资源
– 调整系统配置
# 5. 验证处理结果
– 检查大事务是否已结束
– 检查系统性能是否恢复
– 检查是否有其他影响
# 6. 预防措施
– 优化应用程序设计
– 加强监控和告警
– 定期性能分析
– 建立大事务处理流程
3.3.2 YashanDB大事务故障排查工具
# 1. 数据库视图
– v$session:查看会话信息
– v$transaction:查看事务信息
– v$sql:查看SQL语句信息
– v$active_session_history:查看活跃会话历史
– dba_locks:查看锁信息
– dba_undo_extents:查看undo使用情况
– v$log:查看redo日志信息
# 2. 诊断工具
– AWR (Automatic Workload Repository):自动工作负载仓库
– ASH (Active Session History):活跃会话历史
– ADDM (Automatic Database Diagnostic Monitor):自动数据库诊断监控器
– SQL Tuning Advisor:SQL调优顾问
– Enterprise Manager:企业管理器
# 3. 操作系统工具
– top:查看系统资源使用情况
– iostat:查看I/O使用情况
– vmstat:查看虚拟内存使用情况
– netstat:查看网络使用情况
# 4. 第三方工具
– Toad:数据库管理工具
– SQL Developer:SQL开发工具
– Navicat:数据库管理工具
– Prometheus + Grafana:监控和可视化工具
Part04-生产案例与实战讲解
4.1 YashanDB大事务拆分案例一
案例背景:某企业数据库系统出现大事务,导致系统性能下降,需要及时处理。
# 1. 环境信息
– 数据库版本:YashanDB 19c
– 操作系统:Oracle Linux 9.3
– 硬件配置:8核CPU,32GB内存,1TB SSD
– 业务类型:OLTP
# 2. 问题描述
– 系统性能下降,用户反映操作缓慢
– 监控系统告警,发现大事务
– 数据库连接数增加,资源使用率高
# 3. 故障排查
# 查看大事务
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
SID SERIAL# USERNAME STATUS SQL_ID SESSION_AGE_SECONDS TRANSACTION_AGE_SECONDS USED_UBLK USED_UREC
——- ———- ———- ——– ————- ——————- ———————— ———- ———-
123 456 FGEDU ACTIVE a1b2c3d4e5f6 3600 600 5000 50000
# 查看大事务的SQL语句
SQL> SELECT sql_text FROM v$sql WHERE sql_id = ‘a1b2c3d4e5f6’;
SQL_TEXT
—————————————-
UPDATE fgedu.orders SET status = ‘COMPLETED’ WHERE order_date < SYSDATE - 30;
# 查看执行计划
SQL> EXPLAIN PLAN FOR UPDATE fgedu.orders SET status = ‘COMPLETED’ WHERE order_date < SYSDATE - 30;
Explained.
SQL> SELECT * FROM TABLE(dbms_xplan.display);
PLAN_TABLE_OUTPUT
—————————————-
Plan hash value: 1234567890
——————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————-
| 0 | UPDATE STATEMENT | | 100K| 1000K| 1000 (5)| 00:00:01 |
| 1 | UPDATE | ORDERS | | | | |
| 2 | FULL TABLE SCAN| ORDERS | 100K| 1000K| 1000 (5)| 00:00:01 |
——————————————————————————-
# 4. 处理措施
# 优化SQL语句
SQL> CREATE INDEX idx_orders_order_date ON fgedu.orders(order_date);
Index created.
# 拆分大事务
SQL> BEGIN
2 FOR i IN 1..10 LOOP
3 UPDATE fgedu.orders
4 SET status = ‘COMPLETED’
5 WHERE order_date < SYSDATE - 30
6 AND rownum <= 10000;
7 COMMIT;
8 EXIT WHEN SQL%ROWCOUNT = 0;
9 END LOOP;
10 END;
11 /
PL/SQL procedure successfully completed.
# 终止大事务
SQL> ALTER SYSTEM KILL SESSION ‘123,456’ IMMEDIATE;
System altered.
# 5. 验证结果
# 检查大事务是否已结束
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
no rows selected
# 检查系统性能是否恢复
$ sar -u 1 5
Linux 5.4.0-80-generic (fgedu.net.cn) 04/01/2026 _x86_64_ (8 CPU)
10:00:00 AM CPU %user %nice %system %iowait %steal %idle
10:00:01 AM all 5.23 0.00 1.25 0.00 0.00 93.52
10:00:02 AM all 4.88 0.00 1.12 0.00 0.00 93.99
10:00:03 AM all 5.12 0.00 1.35 0.00 0.00 93.53
10:00:04 AM all 4.95 0.00 1.28 0.00 0.00 93.77
10:00:05 AM all 5.32 0.00 1.45 0.00 0.00 93.23
Average: all 5.10 0.00 1.31 0.00 0.00 93.59
# 6. 预防措施
# 优化应用程序设计
– 拆分大事务为小事务
– 使用批量处理处理大量数据
– 合理设置事务隔离级别
# 加强监控和告警
– 配置大事务监控
– 设置合理的告警阈值
– 定期分析大事务
# 系统配置优化
– 增加共享池和PGA大小
– 设置事务超时参数
– 优化I/O配置
4.2 YashanDB大事务拆分案例二
案例背景:某电商系统在大促期间出现大事务,导致系统响应缓慢,需要及时处理。
# 1. 环境信息
– 数据库版本:YashanDB 19c
– 操作系统:Oracle Linux 9.3
– 硬件配置:16核CPU,64GB内存,2TB SSD
– 业务类型:OLTP,大促期间高并发
# 2. 问题描述
– 大促期间系统响应缓慢
– 监控系统告警,发现大量大事务
– 数据库连接数达到上限,资源使用率高
# 3. 故障排查
# 查看大事务
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
SID SERIAL# USERNAME STATUS SQL_ID SESSION_AGE_SECONDS TRANSACTION_AGE_SECONDS USED_UBLK USED_UREC
——- ———- ———- ——– ————- ——————- ———————— ———- ———-
123 456 FGEDU ACTIVE a1b2c3d4e5f6 3600 600 10000 100000
234 567 FGEDU ACTIVE f6e5d4c3b2a1 1800 300 5000 50000
345 678 FGEDU ACTIVE g7h8i9j0k1l2 1200 200 3000 30000
# 查看大事务的SQL语句
SQL> SELECT sql_text FROM v$sql WHERE sql_id = ‘a1b2c3d4e5f6’;
SQL_TEXT
—————————————-
INSERT INTO fgedu.order_items SELECT * FROM fgedu.temp_order_items;
SQL> SELECT sql_text FROM v$sql WHERE sql_id = ‘f6e5d4c3b2a1’;
SQL_TEXT
—————————————-
UPDATE fgedu.orders SET total_amount = (SELECT SUM(price * quantity) FROM fgedu.order_items WHERE order_id = orders.order_id);
# 查看执行计划
SQL> EXPLAIN PLAN FOR INSERT INTO fgedu.order_items SELECT * FROM fgedu.temp_order_items;
Explained.
SQL> SELECT * FROM TABLE(dbms_xplan.display);
PLAN_TABLE_OUTPUT
—————————————-
Plan hash value: 1234567890
——————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————-
| 0 | INSERT STATEMENT | | 10M| 100M| 10000 (5)| 00:00:01 |
| 1 | LOAD TABLE CONVENTIONAL | ORDER_ITEMS | | | | |
| 2 | TABLE ACCESS FULL| TEMP_ORDER_ITEMS | 10M| 100M| 10000 (5)| 00:00:01 |
——————————————————————————-
# 4. 处理措施
# 优化SQL语句
# 对于批量插入,使用批量处理
SQL> BEGIN
2 FOR i IN 1..100 LOOP
3 INSERT INTO fgedu.order_items
4 SELECT * FROM fgedu.temp_order_items
5 WHERE rownum <= 100000;
6 COMMIT;
7 DELETE FROM fgedu.temp_order_items WHERE rownum <= 100000;
8 COMMIT;
9 EXIT WHEN SQL%ROWCOUNT = 0;
10 END LOOP;
11 END;
12 /
PL/SQL procedure successfully completed.
# 优化UPDATE语句,使用索引
SQL> CREATE INDEX idx_order_items_order_id ON fgedu.order_items(order_id);
Index created.
SQL> UPDATE /*+ PARALLEL(4) */ fgedu.orders
SET total_amount = (SELECT SUM(price * quantity)
FROM fgedu.order_items
WHERE order_id = orders.order_id);
# 终止大事务
SQL> ALTER SYSTEM KILL SESSION ‘123,456’ IMMEDIATE;
SQL> ALTER SYSTEM KILL SESSION ‘234,567’ IMMEDIATE;
SQL> ALTER SYSTEM KILL SESSION ‘345,678’ IMMEDIATE;
# 5. 验证结果
# 检查大事务是否已结束
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
no rows selected
# 检查系统性能是否恢复
$ sar -u 1 5
Linux 5.4.0-80-generic (fgedu.net.cn) 04/01/2026 _x86_64_ (16 CPU)
10:00:00 AM CPU %user %nice %system %iowait %steal %idle
10:00:01 AM all 15.23 0.00 3.25 0.00 0.00 81.52
10:00:02 AM all 14.88 0.00 3.12 0.00 0.00 81.99
10:00:03 AM all 15.12 0.00 3.35 0.00 0.00 81.53
10:00:04 AM all 14.95 0.00 3.28 0.00 0.00 81.77
10:00:05 AM all 15.32 0.00 3.45 0.00 0.00 81.23
Average: all 15.10 0.00 3.31 0.00 0.00 81.59
# 6. 预防措施
# 优化应用程序设计
– 使用批量处理处理大量数据
– 避免在事务中进行大量数据操作
– 合理设置事务隔离级别
# 加强监控和告警
– 配置大事务监控
– 设置合理的告警阈值
– 大促期间安排专人监控
# 系统配置优化
– 增加共享池和PGA大小
– 设置事务超时参数
– 优化I/O配置,使用RAID 10
4.3 YashanDB大事务拆分案例三
案例背景:某金融系统出现大事务,导致数据库备份失败,需要及时处理。
# 1. 环境信息
– 数据库版本:YashanDB 19c
– 操作系统:Oracle Linux 9.3
– 硬件配置:12核CPU,48GB内存,1.5TB SSD
– 业务类型:OLTP,金融交易
# 2. 问题描述
– 数据库备份失败,报错”ORA-01555: snapshot too old”
– 监控系统告警,发现大事务
– 数据库性能下降,交易响应缓慢
# 3. 故障排查
# 查看大事务
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
SID SERIAL# USERNAME STATUS SQL_ID SESSION_AGE_SECONDS TRANSACTION_AGE_SECONDS USED_UBLK USED_UREC
——- ———- ———- ——– ————- ——————- ———————— ———- ———-
123 456 FGEDU ACTIVE a1b2c3d4e5f6 7200 3600 20000 200000
# 查看大事务的SQL语句
SQL> SELECT sql_text FROM v$sql WHERE sql_id = ‘a1b2c3d4e5f6’;
SQL_TEXT
—————————————-
BEGIN
FOR i IN 1..1000 LOOP
UPDATE fgedu.transactions SET status = ‘COMPLETED’ WHERE transaction_id = i;
— 模拟外部调用
dbms_lock.sleep(1);
END LOOP;
COMMIT;
END;
# 4. 处理措施
# 终止大事务
SQL> ALTER SYSTEM KILL SESSION ‘123,456’ IMMEDIATE;
System altered.
# 优化事务设计
# 原事务
BEGIN
FOR i IN 1..1000 LOOP
UPDATE fgedu.transactions SET status = ‘COMPLETED’ WHERE transaction_id = i;
— 模拟外部调用
dbms_lock.sleep(1);
END LOOP;
COMMIT;
END;
/
# 优化后事务
BEGIN
FOR i IN 1..1000 LOOP
UPDATE fgedu.transactions SET status = ‘COMPLETED’ WHERE transaction_id = i;
— 每100条提交一次
IF MOD(i, 100) = 0 THEN
COMMIT;
END IF;
END LOOP;
COMMIT;
END;
/
# 优化外部调用
# 将外部调用移到事务外
BEGIN
FOR i IN 1..1000 LOOP
UPDATE fgedu.transactions SET status = ‘COMPLETED’ WHERE transaction_id = i;
— 每100条提交一次
IF MOD(i, 100) = 0 THEN
COMMIT;
— 模拟外部调用
dbms_lock.sleep(1);
END IF;
END LOOP;
COMMIT;
END;
/
# 5. 验证结果
# 检查大事务是否已结束
SQL> SELECT s.sid, s.serial#, s.username, s.status, s.sql_id,
(SYSDATE – s.logon_time) * 24 * 60 * 60 AS session_age_seconds,
(SYSDATE – t.start_time) * 24 * 60 * 60 AS transaction_age_seconds,
t.used_ublk, t.used_urec
FROM v$session s
JOIN v$transaction t ON s.taddr = t.addr
ORDER BY t.used_ublk DESC, transaction_age_seconds DESC;
no rows selected
# 重新执行备份
RMAN> BACKUP DATABASE PLUS ARCHIVELOG;
Starting backup at 2026-04-01 10:00:00
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=123 device type=DISK
channel ORA_DISK_1: starting full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00001 name=/yashanb/fgdata/fgedudb/system01.dbf
input datafile file number=00002 name=/yashanb/fgdata/fgedudb/sysaux01.dbf
input datafile file number=00003 name=/yashanb/fgdata/fgedudb/undotbs01.dbf
input datafile file number=00004 name=/yashanb/fgdata/fgedudb/users01.dbf
input datafile file number=00005 name=/yashanb/fgdata/fgedudb/fgedutbs01.dbf
channel ORA_DISK_1: starting piece 1 at 2026-04-01 10:00:00
channel ORA_DISK_1: finished piece 1 at 2026-04-01 10:05:00
piece handle=/yashanb/backup/fgedudb_full_20260401_12345.bkp tag=TAG20260401T100000 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:05:00
channel ORA_DISK_1: starting archived log backup set
channel ORA_DISK_1: specifying archived log(s) in backup set
input archived log thread=1 sequence=100
input archived log thread=1 sequence=101
input archived log thread=1 sequence=102
channel ORA_DISK_1: starting piece 1 at 2026-04-01 10:05:00
channel ORA_DISK_1: finished piece 1 at 2026-04-01 10:05:30
piece handle=/yashanb/backup/fgedudb_arch_20260401_12346.bkp tag=TAG20260401T100500 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:30
Finished backup at 2026-04-01 10:05:30
# 6. 预防措施
# 优化应用程序设计
– 避免在事务中进行外部调用
– 合理设置事务范围,及时提交或回滚
– 使用批量处理处理大量数据
# 加强监控和告警
– 配置大事务监控
– 设置合理的告警阈值
– 定期检查大事务
# 系统配置优化
– 增加undo表空间大小
– 设置合理的undo_retention参数
– 优化备份策略,避开业务高峰期
Part05-风哥经验总结与分享
5.1 YashanDB大事务拆分经验总结
YashanDB大事务拆分经验总结:
- 预防为主:通过合理的设计和优化,预防大事务的发生
- 拆分策略:根据大事务的特点,选择合适的拆分策略
- 批量处理:对于大量数据的操作,使用批量处理技术
- 并行处理:利用并行处理技术,提高处理效率
- 监控和告警:建立大事务监控和告警机制,及时发现和处理大事务
- 错误处理:添加错误处理机制,确保拆分过程的可靠性
- 数据验证:处理完成后,验证数据的完整性
- 持续优化:根据实际情况,持续优化拆分策略
5.2 YashanDB大事务拆分检查清单
– [ ] 大事务监控机制是否建立
– [ ] 大事务告警阈值是否合理
– [ ] 大事务拆分策略是否确定
– [ ] 批量处理大小是否合理
– [ ] 并行处理是否配置
– [ ] 错误处理机制是否完善
– [ ] 数据验证机制是否建立
– [ ] 监控和告警是否到位
– [ ] 拆分后的性能是否改善
– [ ] 拆分过程是否文档化
# 大事务预防检查清单
– [ ] 事务范围是否合理
– [ ] SQL语句是否优化
– [ ] 批量操作是否合理
– [ ] 外部调用是否移出事务
– [ ] 事务隔离级别是否合适
– [ ] 提交频率是否合理
– [ ] 系统资源是否充足
– [ ] 监控和告警是否到位
5.3 YashanDB大事务拆分工具推荐
YashanDB大事务拆分常用工具:
- 数据库工具:SQL*Plus、SQL Developer、PL/SQL Developer
- 脚本工具:Shell脚本、Python脚本、Perl脚本
- 监控工具:Enterprise Manager、Prometheus + Grafana、Zabbix
- 诊断工具:AWR、ASH、ADDM、SQL Tuning Advisor
- 并行处理工具:Oracle Parallel Processing、DBMS_PARALLEL_EXECUTE
- 消息队列:Oracle Advanced Queuing、Kafka、RabbitMQ
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
