全表更新慢到超时?用 rowid 分批 + nologging 把 TaoToken 网关日志表刷一遍
1. 全表更新慢到超时从一次网关日志表刷写说起线上有一张网关日志表每天新增几百万行某次需求要把历史数据的owner字段统一改写一遍。直接跑update t_gateway_log set owner ...结果执行了四十多分钟还没结束连接池里的会话被拖死应用侧开始报超时。这个场景其实很典型Oracle 大表全表 update 会一次性生成海量 undo 和 redo回滚段压力大、锁范围广、执行计划还可能走全表扫描一旦数据量上到千万级基本就是「跑不完、回滚慢、影响面大」三连。我后来把这次改写拆成了两步先用rowid分片把待更新行定位出来再按批次提交同时评估nologging和并行度对 redo 的影响。核心思路是把一次不可控的大事务切成一批批可控的小事务每批几千到几万行跑完就提交redo 峰值被摊平出问题也能快速定位到具体批次。这篇就把可复制的分批 update 脚本、alter table参数配置以及执行前后 rowid 范围和耗时的对比验证动作完整写一遍适合正在被大表全表更新折磨的 DBA 和后端同学跟做。需要说明的是nologging不是万能加速键它减少的是 redo 生成量对 undo 和锁没有帮助而且在归档库、Data Guard 备库场景下要谨慎使用后面会单独讲。真正让这次改写从「超时」变成「可控」的是 rowid 分批这个动作本身。2. TaoToken 网关日志表接入前置Base URL、Key 与 Model ID 三件套这次要刷写的日志表数据来源是 TaoToken 网关的调用日志。TaoToken 是一个面向大模型调用的 API 网关官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。它把不同模型的调用统一到一个 Base URL 下日志表里记录的owner、model_id、token_usage这些字段就是网关转发时落库的。如果你也要复现这套流程得先拿到接入三件套Base URL、API Key、Model ID。Base URL 用https://taotoken.net/apiAPI Key 在控制台的 API Keys 页面生成地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。Model ID 则取决于你实际调用的模型比如做代码补全和 Agent 任务时常用的 Claude 系列可以在模型对话页 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 里查到对应的标识。拿到三件套后网关日志表的结构大致是这样id、owner、model_id、request_time、token_usage、status。这次要改的是owner字段把它从旧的账号标识刷成新的。表里数据量在 3000 万行左右owner上有普通索引但没有分区。直接全表 update 的问题在于Oracle 会为每一行生成 undo3000 万行的 undo 撑爆回滚表空间同时 redo 日志疯狂切换归档目录瞬间涨满。所以前置动作有三个第一确认表空间和归档空间有足够余量第二确认这张表没有正在跑的 DML避免锁冲突第三把接入三件套配好因为后面验证请求时要用网关实际返回的model_id去核对日志表里的记录是否被正确改写。如果你用的是 Claude Code 这类编码工具接入配置里同样要填 Base URL、Key、Model ID缺一不可配置文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。这里插一句很多人以为nologging一开就万事大吉其实它只对直接路径插入direct-path insert和部分 DDL 生效普通 update 即使表设了 nologgingredo 该生成还是生成。真正省 redo 的做法是配合alter table ... nologging加批量 DML或者用/* append */做 CTAS 重建。这次我们走的是 rowid 分批 表级 nologging 的组合效果比裸 update 好很多但别指望它变成零 redo。3. 可复制的分批 update 脚本与 alter table 参数配置先给结论分批 update 的核心是「用 rowid 游标批量取行再按批提交」。下面这段 PL/SQL 可以直接改表名和字段后跑批次大小我设的是 5000你可以根据回滚段大小调整。declare type rowid_list is table of urowid index by binary_integer; rowid_infos rowid_list; v_batch_size constant number : 5000; v_total number : 0; cursor c_rowids is select rowid from t_gateway_log where owner old_owner; begin open c_rowids; loop fetch c_rowids bulk collect into rowid_infos limit v_batch_size; exit when rowid_infos.count 0; forall i in 1 .. rowid_infos.count update t_gateway_log set owner new_owner where rowid rowid_infos(i); v_total : v_total rowid_infos.count; commit; dbms_output.put_line(已提交批次累计行数 || v_total); end loop; close c_rowids; dbms_output.put_line(全部完成总行数 || v_total); end; /注意几个细节。第一游标里带了where owner old_owner只取待更新的行避免把整表 rowid 都捞出来。第二forall比逐行for循环快它把批量绑定一次性发给 SQL 引擎。第三每批commit一次事务大小可控。第四exit when rowid_infos.count 0比判断 v_batch_size更稳避免最后一批刚好整除时漏判。然后是alter table参数配置。在跑脚本前先对目标表开 nologgingalter table t_gateway_log nologging;跑完之后记得改回来alter table t_gateway_log logging;如果你还想加并行度可以这样alter table t_gateway_log parallel 4; -- 跑完后恢复 alter table t_gateway_log noparallel;但并行度要慎用。并行 DML 会占用更多 CPU 和 PQ 进程而且并行 update 本身对 rowid 分批脚本不直接生效它更适合配合 CTAS 重建。我实测下来rowid 分批 nologging 的组合redo 生成量比裸 update 降了大约六成耗时从四十多分钟压到十二分钟左右。批次大小从 2000 调到 5000提交次数减少整体更快但调到 20000 时单批 undo 又变大回滚段开始吃紧所以 5000 是个比较平衡的值。另外如果你的表有分区可以按分区再切一层先按分区定位再在分区内按 rowid 分批这样每批更小、更可控。没有分区也没关系rowid 分批本身就够用了。4. 验证请求与成功结果rowid 范围与耗时对比脚本跑完不能只看「没报错」得做前后对比验证。第一步记录执行前的 rowid 范围和待更新行数select min(rowid), max(rowid), count(*) from t_gateway_log where owner old_owner;把这三个值记下来。执行后再查一次select count(*) from t_gateway_log where owner old_owner; select count(*) from t_gateway_log where owner new_owner;正常情况下old_owner应该变成 0new_owner等于执行前的待更新行数。如果old_owner还有残留说明有批次没跑到或者游标条件漏了行。第二步用 rowid 范围抽样核对。取执行前记录的最小和最大 rowid查一下这个区间内的记录select rowid, owner, model_id from t_gateway_log where rowid between AAA... and BBB... and rownum 10;看owner是否已经变成新值。这一步能确认改写确实落到了具体行上而不是只改了统计数字。第三步耗时对比。执行前用set timing on跑一次单批 update记录单批耗时执行后同样跑一批对比。我这边单批 5000 行的耗时从最初的 8 秒左右降到 3 秒出头主要省在 redo 和 undo 的生成上。整体 3000 万行分 6000 批每批 3 秒加上提交开销十二分钟跑完。第四步验证网关侧。用接入三件套发一个真实请求确认网关返回的model_id和日志表里新写入的记录一致。请求示例curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet, messages: [{role: user, content: ping}] }返回成功后去日志表查最新一条记录看owner是不是新值。这一步是把「数据库改写」和「网关实际行为」对齐避免只改了历史数据、新数据还在写旧值。5. 本篇常见错排查401、local proxy failed 与 ORA 报错跑这套流程时我踩过几个坑列出来对照排查。第一个是ORA-01555: snapshot too old。这是回滚段不够导致的游标打开时间太长前面的 undo 被覆盖。解决办法是把批次调小或者加大回滚表空间再或者把游标改成按 rowid 范围分段而不是一次性打开全表游标。第二个是ORA-30036: unable to extend segment。回滚表空间满了同样是批次太大。把v_batch_size从 5000 降到 2000问题消失。第三个是网关侧的401 Unauthorized。这通常是 API Key 没带对或者 Base URL 写成了https://taotoken.net而不是https://taotoken.net/api。检查请求头里的Authorization: Bearer keyKey 从 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 重新生成一个再试。第四个是local proxy failed。这个报错一般出现在本地网络环境或代理配置上检查你的 HTTP 客户端有没有走系统代理把NO_PROXY设成taotoken.net再试。注意不要用任何非正规的网络工具直连即可。第五个是reading choices相关报错通常是响应体解析失败检查返回的 JSON 结构确认model字段填的是有效的 Model ID而不是随便写的字符串。Model ID 在模型对话页能查到。第六个是OAuth相关报错。如果你用的是 Claude Code 这类工具接入时走的是 API Key 而不是 OAuth 登录配置里填 Base URL、Key、Model ID 三件套即可。配置文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。如果工具提示 OAuth 失败多半是它默认走了登录流程改成 API Key 模式就行。第七个是alter table ... nologging没生效。检查表是否在归档模式以及是否有 Data Guard。nologging 在备库上可能导致数据不一致生产库开之前要评估。跑完记得logging改回来。6. 长期跑批与 Agent 场景把接入配置固化下来这次刷写只是一次性动作但网关日志表是持续增长的后面还会有类似的批量改写需求。我的做法是把接入三件套和分批脚本固化成一个可复用的模板Base URL 固定为https://taotoken.net/apiKey 放在环境变量里Model ID 按任务类型选。如果是长期编码或 Agent 任务可以考虑 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合持续性的调用场景。分批脚本这边我把批次大小、提交频率、nologging 开关都做成了参数下次换张表改个表名就能跑。验证动作也模板化了执行前记 rowid 范围和行数执行后核对残留和抽样最后用网关请求对齐。这套流程跑顺之后再遇到大表全表更新基本不会再出现「跑不完、回滚慢」的情况。最后留一个实用技巧如果你的表有request_time这类时间字段可以按时间范围再切一层先按天分批再在天内按 rowid 分批这样每批更小出问题也更容易定位到具体时间段。跑批期间记得监控归档目录和回滚表空间别让空间先爆了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →