ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ORACLE游标循环实战:用TaoToken统一Key跑通PL/SQL批量处理

ORACLE游标循环实战:用TaoToken统一Key跑通PL/SQL批量处理 1. 从一次批量更新卡死说起ORACLE 游标循环到底该怎么写ORACLE 游标循环是 PL/SQL 里处理批量数据最常用的手段简单说就是让 SQL 查询结果集像流水线一样一行行或一批批交给程序处理。它适合谁适合每天要跑对账、批量更新状态、清洗历史数据的后端和 DBA尤其是那种「几百万行表要逐条算逻辑再写回」的场景。我见过太多人第一次写游标要么忘了exit when导致死循环要么在循环里逐行update把库拖垮最后只能 kill session。这篇聚焦 ORACLE 游标循环在 PL/SQL 批量数据处理中的落地从显式游标 FOR LOOP 到 BULK COLLECT再结合 TaoToken 统一 Key/API 通道管理调用凭证。为什么要把游标和 TaoToken 放一起因为现在很多批量任务不只是纯数据库操作还要在循环里调用大模型做字段补全、文本分类、地址标准化。如果每个脚本都硬编码一个 Key凭证散落各处换一次 Key 要改十几个文件。用 TaoToken 把调用凭证统一管起来游标循环里只管发请求Key 和通道交给一个入口。先明确三种游标循环的适用边界这是后面所有模板的基础方式写法特征适用场景主要风险LOOP FETCH手动 open/fetch/close需要精细控制、分批提交漏写 exit when 死循环WHILE FETCH先 fetch 一次再 while逻辑判断在循环条件里漏写第二个 fetch 死循环FOR LOOPfor r in cur loop绝大多数只读遍历隐式游标无法中途改查询BULK COLLECTfetch ... bulk collect into大批量、要限流提交集合内存占用需评估我试过在一个 800 万行的用户表上做标签回填最初用 FOR LOOP 逐行 update跑了 40 分钟还没结束后来改成 BULK COLLECT 每 1000 行提交一次压到 3 分钟内。差别就在「逐行往返」和「批量往返」。所以这篇不会只给你语法而是给你能直接复制、能核对结果的完整模板。核心检索词先摆出来ORACLE 游标循环、PL/SQL 批量处理、BULK COLLECT、TaoToken 统一 Key。你如果是来找「游标循环怎么写不死循环」或者「批量提交怎么配」的往下看步骤就行。2. TaoToken 前置准备统一 Key 与 API 通道管理在游标循环里调用外部模型之前先把凭证这件事理顺。TaoToken 在这里扮演的角色是统一入口你不需要在 PL/SQL 里散落多个厂商的 Key而是通过一个 Base URL 和一个 Key 走所有模型请求。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址不带 UTM 参数配置时别把跟踪参数拼进去。为什么批量任务特别需要这个因为 PL/SQL 里发 HTTP 请求本身就不算优雅如果再叠加多套凭证管理维护成本会爆炸。统一 Key 之后游标循环里的调用逻辑只关心「传什么、拿什么」不关心「用哪个 Key」。换 Key 只改一处所有存储过程、定时任务、脚本全部生效。前置准备分三步都是可复制的第一步拿到 Key。进入控制台创建 API Key路径是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面生成。生成后立刻复制保存页面通常只完整显示一次。API Keys 直达 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。第二步确认你要用的模型 ID。不同任务用不同模型批量分类可以用轻量模型复杂推理用强模型。模型对话页面可以先手动验证一次 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。在这里发一条测试消息确认 Key 和通道都通再去写 PL/SQL。第三步决定调用方式。PL/SQL 里发 HTTP 一般用UTL_HTTP或APEX_WEB_SERVICE。如果你用的是 Oracle APEX 环境APEX_WEB_SERVICE.MAKE_REST_REQUEST更省事纯数据库环境用UTL_HTTP配DBMS_LOB处理返回体。两种方式下面都会给模板。这里要提醒一个坑数据库服务器要能访问外网且需要配置 ACL访问控制列表。Oracle 12c 以后默认禁止网络访问必须显式授权。授权语句模板BEGIN DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE( host taotoken.net, ace xs$ace_type( privilege_list xs$name_list(http, http_proxy), principal_name YOUR_DB_USER, principal_type xs_acl.ptype_db ) ); COMMIT; END; /把YOUR_DB_USER换成你实际执行存储过程的用户。这一步不做后面所有 HTTP 调用都会报ORA-24247: network access denied by access control list。这个报错在排障章节还会再提。关于长期编码和 Agent 场景如果你是要把游标批量任务做成常态化流水线可以了解 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 配置细节以文档为准。3. 可复制配置游标循环模板与批量提交参数这一节是全文的技术核心给你三套能直接跑的模板外加 TaoToken 调用的配置片段。所有模板都基于一张示例表users字段id、name、status你可以替换成自己的表。3.1 显式游标 FOR LOOP 模板最稳推荐首选FOR LOOP 的最大好处是自动 open/fetch/close不会死循环也不会忘记关游标。适合只读遍历加逻辑处理CREATE OR REPLACE PROCEDURE proc_cursor_for AS CURSOR cur IS SELECT id, name FROM users WHERE status PENDING; BEGIN FOR r IN cur LOOP -- 这里写你的业务逻辑r.id / r.name 直接可用 DBMS_OUTPUT.PUT_LINE(r.id || - || r.name); END LOOP; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; /注意EXCEPTION里我加了RAISE把异常继续往上抛方便定时任务捕获。原示例只ROLLBACK不抛问题会被吞掉排查时很痛苦。3.2 LOOP FETCH 模板需要精细控制时用当你需要在循环中途根据条件exit或者要手动控制提交节奏时用这个CREATE OR REPLACE PROCEDURE proc_cursor_loop AS CURSOR cur IS SELECT id, name FROM users WHERE status PENDING; v_id users.id%TYPE; v_name users.name%TYPE; v_cnt PLS_INTEGER : 0; BEGIN OPEN cur; LOOP FETCH cur INTO v_id, v_name; EXIT WHEN cur%NOTFOUND; -- 这行绝对不能少 DBMS_OUTPUT.PUT_LINE(v_id || - || v_name); v_cnt : v_cnt 1; IF MOD(v_cnt, 1000) 0 THEN COMMIT; -- 每 1000 行提交一次 END IF; END LOOP; CLOSE cur; COMMIT; EXCEPTION WHEN OTHERS THEN IF cur%ISOPEN THEN CLOSE cur; END IF; ROLLBACK; RAISE; END; /EXIT WHEN cur%NOTFOUND是防死循环的命门。漏了它FETCH到末尾后变量保持最后一行值循环永远不退出。3.3 BULK COLLECT 模板大批量首选BULK COLLECT 一次取一批到集合减少上下文切换。配合LIMIT控制每批大小避免 PGA 内存爆掉CREATE OR REPLACE PROCEDURE proc_cursor_bulk AS CURSOR cur IS SELECT id, name FROM users WHERE status PENDING; TYPE t_id IS TABLE OF users.id%TYPE; TYPE t_name IS TABLE OF users.name%TYPE; v_ids t_id; v_names t_name; v_limit PLS_INTEGER : 1000; BEGIN OPEN cur; LOOP FETCH cur BULK COLLECT INTO v_ids, v_names LIMIT v_limit; EXIT WHEN v_ids.COUNT 0; FOR i IN 1 .. v_ids.COUNT LOOP DBMS_OUTPUT.PUT_LINE(v_ids(i) || - || v_names(i)); END LOOP; COMMIT; -- 每批提交 END LOOP; CLOSE cur; EXCEPTION WHEN OTHERS THEN IF cur%ISOPEN THEN CLOSE cur; END IF; ROLLBACK; RAISE; END; /LIMIT 1000是经验值一般 500 到 5000 之间。太小提交频繁太大内存吃紧。你可以根据行宽调整。3.4 TaoToken 调用配置片段在游标循环里调用模型核心是把 Base URL、Key、Model ID 三件套配好。下面是一个 JSON 配置片段放在应用侧或配置表里PL/SQL 读取后拼请求{ base_url: https://taotoken.net/api, api_key: sk-你的TaoToken密钥, model_id: 你的模型ID, timeout_ms: 30000, max_retries: 2 }如果你用 APEX可以在APEX_WEB_SERVICE.MAKE_REST_REQUEST里直接引用DECLARE v_clob CLOB; BEGIN v_clob : APEX_WEB_SERVICE.MAKE_REST_REQUEST( p_url https://taotoken.net/api/v1/chat/completions, p_http_method POST, p_username NULL, p_password sk-你的TaoToken密钥, p_body {model:你的模型ID,messages:[{role:user,content:测试}]} ); DBMS_OUTPUT.PUT_LINE(DBMS_LOB.SUBSTR(v_clob, 500, 1)); END; /注意p_password传 Keyp_username留空。请求体里的model换成你在模型对话页面验证过的 ID。这套配置和 Claude Code 接入时的三件套逻辑一致Base URL 指向https://taotoken.net/apiKey 用生成的密钥Model ID 用实际模型名。Claude Code 相关接入可参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。4. 验证请求与执行计划核对跑通并确认结果模板写完不能直接上生产先验证两件事请求通不通执行计划对不对。4.1 验证 TaoToken 请求先用最简单的匿名块发一次请求确认网络和凭证没问题SET SERVEROUTPUT ON SIZE UNLIMITED; DECLARE v_req UTL_HTTP.REQ; v_resp UTL_HTTP.RESP; v_body CLOB; v_text VARCHAR2(32767); BEGIN UTL_HTTP.SET_TRANSFER_TIMEOUT(30); v_req : UTL_HTTP.BEGIN_REQUEST(https://taotoken.net/api/v1/chat/completions, POST); UTL_HTTP.SET_HEADER(v_req, Content-Type, application/json); UTL_HTTP.SET_HEADER(v_req, Authorization, Bearer sk-你的TaoToken密钥); UTL_HTTP.WRITE_TEXT(v_req, {model:你的模型ID,messages:[{role:user,content:ping}]}); v_resp : UTL_HTTP.GET_RESPONSE(v_req); DBMS_OUTPUT.PUT_LINE(HTTP Status: || v_resp.status_code); BEGIN LOOP UTL_HTTP.READ_TEXT(v_resp, v_text, 32767); v_body : v_body || v_text; END LOOP; EXCEPTION WHEN UTL_HTTP.END_OF_BODY THEN NULL; END; UTL_HTTP.END_RESPONSE(v_resp); DBMS_OUTPUT.PUT_LINE(DBMS_LOB.SUBSTR(v_body, 1000, 1)); END; /成功时你会看到HTTP Status: 200和一段 JSON 返回。如果状态码是 401说明 Key 不对或没带Bearer前缀如果是 403多半是 ACL 没配。4.2 验证游标循环结果跑完存储过程后用对照查询核对处理行数-- 处理前统计 SELECT COUNT(*) FROM users WHERE status PENDING; -- 执行存储过程 BEGIN proc_cursor_bulk; END; / -- 处理后统计确认状态已更新 SELECT COUNT(*) FROM users WHERE status PENDING; SELECT COUNT(*) FROM users WHERE status DONE;两个数字加起来应该等于总行数否则说明有行被漏处理或重复处理。4.3 执行计划验证游标循环慢十有八九是查询本身没走索引。用EXPLAIN PLAN看EXPLAIN PLAN FOR SELECT id, name FROM users WHERE status PENDING; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);重点看TABLE ACCESS是FULL还是BY INDEX ROWID。如果status列没索引全表扫描在百万行表上会拖垮整个循环。加索引CREATE INDEX idx_users_status ON users(status);加完再跑一次EXPLAIN PLAN确认变成索引扫描。这一步做完BULK COLLECT 的提速效果才明显。4.4 批量提交参数核对提交频率直接影响 undo 表空间和性能。用下面查询观察 undo 使用SELECT begin_time, undoblks, maxquerylen FROM v$undostat ORDER BY begin_time DESC FETCH FIRST 5 ROWS ONLY;如果undoblks飙升说明单次提交太大把LIMIT或提交间隔调小。一般每 1000 到 5000 行提交一次比较稳。5. 本篇常见错排查401、ACL、死循环与 OAuth这一节对照真实报错给你定位思路。ORA-24247: network access denied by access control list这是最常见的第一个拦路虎。原因数据库没授权访问taotoken.net。解决执行第 2 节的DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE把主机名和数据库用户换成实际的。执行后可能需要等几秒生效或者COMMIT后重连会话。HTTP 401 UnauthorizedKey 错误或格式不对。检查三点Key 是否完整复制有没有漏字符、请求头是否是Authorization: Bearer sk-xxxBearer 后面有空格、Key 是否已过期或被删除。去 API Keys 页面重新生成一个再试 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。local proxy failed / connection refused数据库服务器到taotoken.net的网络不通。先在数据库主机上用curl或telnet测连通性。如果主机能通但数据库不通还是 ACL 问题如果主机都不通检查防火墙和 DNS。reading choices 相关报错这类通常出现在解析返回 JSON 时字段路径不对。返回体结构是choices[0].message.content如果你按别的路径取就会报错。先用第 4.1 节的匿名块把原始返回打出来确认结构再写解析逻辑。OAuth 相关报错如果你在配置 Claude Code 或其他工具时遇到 OAuth 报错多半是认证方式选错了。TaoToken 的 API 调用用 Key 认证不需要走 OAuth 流程。Claude Code 接入时按文档配置 Base URL、Key、Model ID 三件套即可参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。死循环循环不退出症状存储过程一直跑DBMS_OUTPUT刷屏。原因LOOP 方式漏了EXIT WHEN cur%NOTFOUND或 WHILE 方式漏了第二个FETCH。解决对照第 3 节的模板逐行检查。WHILE 方式记住「进循环前 fetch 一次循环体末尾再 fetch 一次」。ORA-06502: PL/SQL: numeric or value error多半是变量长度不够。v_name定义成VARCHAR2(100)但实际数据超过 100 字符。用%TYPE让变量跟随列定义避免硬编码长度。BULK COLLECT 内存溢出ORA-04030LIMIT设太大或没设。集合一次性装太多行PGA 撑爆。把LIMIT降到 1000 以下或者分批处理。排障时如果拿不准先去模型对话页面手动发一条请求确认通道本身没问题 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。通道通了再查 PL/SQL 侧。接入细节以文档为准 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。6. 把游标批量任务接上统一通道回到实际场景你有一张待处理表游标循环负责遍历TaoToken 负责在循环里提供模型能力。两者结合的关键是「凭证集中、逻辑解耦」。游标模板你直接复制第 3 节的三套按数据量选 FOR LOOP 还是 BULK COLLECTTaoToken 侧把 Base URL 固定为https://taotoken.net/apiKey 从控制台生成Model ID 从模型对话页面确认。如果你要把这套做成长期跑的流水线比如每天定时批量清洗建议走 Coding Plan 管理调用额度 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。控制台统一看用量 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。最后给一个实用技巧在游标循环里调用模型时把请求结果先写进临时表循环结束后再统一 merge 回主表。这样即使中途失败也能从临时表断点续跑不用从头再来。批量任务最怕的就是跑了两小时挂掉重跑又两小时。临时表加批次号续跑时跳过已完成的批次这个习惯能省你很多时间。
返回列表