游标变量本身不影响性能,关键在于SQL执行方式:静态游标编译期确定执行计划,复用高效;动态游标运行期拼接SQL易引发硬解析和安全风险。
oracle 中游标变量(ref cursor)本身不决定性能高低,真正影响开销的是它背后绑定的 sql 执行方式——静态游标用编译期确定的 sql,动态游标用运行期拼接的 sql。优化关键不在“用不用游标变量”,而在于“怎么构造和使用它”。
静态游标为什么通常更快
静态游标(如 CURSOR c IS SELECT ...)在 PL/SQL 编译阶段就完成语法检查、执行计划生成和绑定变量解析。每次调用时直接复用已缓存的执行计划,跳过硬解析开销。
- 隐式使用
%ROWTYPE或显式声明RECORD时,字段结构在编译期固定,无运行时元数据查询成本 - 若带参数(如
CURSOR c(p_dept VARCHAR2) IS SELECT ... WHERE dept = p_dept),仍属静态游标——参数只是绑定值,SQL 文本不变 - 不支持运行时改写查询逻辑,但换来稳定性和可预测性
动态游标开销主要在哪
动态游标(OPEN ref_cursor FOR v_sql)的性能瓶颈集中在运行时:SQL 字符串拼接、硬解析、执行计划生成、权限校验,以及可能的 SQL 注入风险处理。
-
v_sql含拼接字符串(如'WHERE id )时,每种不同值都可能触发新硬解析,尤其当 <code>v_max变化频繁且未用绑定变量 - 即使用了绑定变量(
OPEN rc FOR 'SELECT * FROM t WHERE id = :1' USING v_id),首次执行仍需硬解析;而静态游标在包体编译时已完成 - 动态 SQL 无法被 PL/SQL 编译器静态检查,错误(如表不存在、列名错)只在运行时报
ORA-00942或ORA-00904 - 某些场景下(如分表查询),动态游标不可替代,但应尽量把 SQL 拼接逻辑收束到最小范围,避免在循环内反复
OPEN
游标变量本身不增加额外开销,但容易掩盖问题
REF CURSOR 类型(包括 SYS_REFCURSOR)只是指针容器,内存占用极小。它的“慢”往往来自误用模式,而非类型本身。
- 把本该用静态游标的地方强行改成
OPEN rc FOR 'SELECT ...',等于主动放弃编译期优化 - 在存储过程中返回
SYS_REFCURSOR给应用层是常见且合理做法,但内部构造时仍应优先用静态 SQL 或带绑定变量的动态 SQL - 不要在循环中对同一逻辑反复打开/关闭游标变量——应提取共用 SQL,或改用 BULK COLLECT + LIMIT 批量拉取
- 注意游标变量未关闭不会立即报错,但会持续占用
OPEN_CURSORS限制,长期运行易触发ORA-01000: maximum open cursors exceeded
真正要盯住的不是“静态 or 动态”,而是 SQL 是否复用执行计划、是否规避硬解析、是否暴露给不可信输入。一个拼接了用户输入的静态游标定义(比如用 EXECUTE IMMEDIATE 构造后赋给 REF CURSOR)比规范使用的动态游标更危险也更慢。











