1. 三个参数到底谁在吃内存?先搞清楚它们的分工
open_cursors、sessions、processes 这三个参数,是数据库连接层最容易被混淆的一组。很多人一看到连接数飙升、句柄堆积、内存吃紧,第一反应就是去调 sessions,结果调完发现游标还是不够用,或者进程数先爆了。我试过在一个测试库里把 sessions 从 2280 拉到 3000,结果应用侧依然报 ORA-01000,最后才发现真正卡住的是 open_cursors。
先把这三个参数的定义摆清楚,这是排查的地基。
open_cursors 是单个会话(session)在同一时刻最多能打开的游标数量。游标是什么?你可以把它理解成一条 SQL 语句的执行句柄。每次执行一条 SQL,数据库就会为它分配一个游标。如果应用代码里没有及时关闭游标,或者用了大量动态 SQL、批量操作,单个会话的游标数就会持续堆积。一旦超过 open_cursors 的限制,就会直接抛 ORA-01000: maximum open cursors exceeded。
sessions 是整个实例允许同时存在的会话总数上限。一个会话通常对应一个客户端连接,比如一个 JDBC 连接、一个连接池里的物理连接。sessions 决定了你的连接池最多能开多大,也决定了并发访问的天花板。
processes 是操作系统层面允许数据库实例创建的最大进程数。在 Linux 上,每个会话、每个后台进程、每个并行执行的服务进程都会占用一个 process 名额。Windows 上这个参数对应的是最大线程数。processes 通常是 sessions 的上限约束,因为 sessions 的值一般由 processes 推导而来。
三者的关系可以这样理解:processes 是总盘子,sessions 是盘子里能坐多少人,open_cursors 是每个人手里能同时拿多少把工具。盘子不够大,人坐不下;人坐下了但工具不够,活干不了。内存和句柄的消耗,恰恰就藏在这三层里。
连接泄漏的典型表现是 sessions 持续增长不回落,句柄堆积的典型表现是 open_cursors 逼近上限。而 processes 被打满时,新连接根本建不起来,报错往往是 ORA-00020 或者监听器拒绝连接。搞清楚谁在吃资源,才能对症下药。
这篇内容会带你从查询语句开始,一步步定位到底是哪个参数在报警,然后给出可复制的配置修改动作,最后用实际请求验证资源回收效果。适合正在做数据库连接层排查的开发和运维同学,尤其是遇到游标超限、连接池打满、进程数告警这类问题的场景。
2. TaoToken 前置准备:把排查环境搭起来
在开始排查之前,你需要一个能稳定执行 SQL 并观察结果的环境。如果你本地已经有数据库客户端,可以直接用。如果没有,或者你想在一个统一的入口里管理多个模型的对话和 API 调用,可以先把 TaoToken 的接入准备好。
TaoToken 在这里的角色是提供一个统一的 API 入口,方便你在排查过程中调用模型来辅助分析报错日志、生成排查脚本,或者对比不同参数配置下的行为差异。它不是数据库本身,而是你排查工作流里的一个辅助工具。
第一步,打开官网了解整体能力:
https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=第二步,进入控制台创建 API Key。路径是 console 页面,找到 API Keys 管理入口:
https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite在 API Keys 页面点击创建,复制生成的 Key。这个 Key 后面会用在配置文件的鉴权字段里。注意不要把它提交到公开仓库,建议放在环境变量或者本地配置文件中。
第三步,如果你需要长期做编码和 Agent 相关的排查工作,可以了解一下 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite第四步,准备好接入文档,后面配置 Base URL 和 Model ID 时会用到:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewriteAPI 的基础地址是:
https://taotoken.net/api这个地址不加 UTM 参数,直接作为 Base URL 使用。
如果你用的是 Claude Code 这类工具,可以参考 Anthropic 兼容的接入方式:
https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ClaudeCodeAnthropic&utm_campaign=rewrite前置准备的核心是三件套:Base URL、API Key、Model ID。无论你用的是哪种客户端,这三个字段的填写逻辑是一致的。Base URL 填https://taotoken.net/api,API Key 填你刚创建的那串字符,Model ID 根据你实际要调用的模型填写,具体可选项在文档页有说明。
把这三样准备好之后,你就可以在排查数据库参数的同时,用模型来帮你解读报错、生成查询语句、或者对比不同配置的差异。接下来进入实际的配置环节。
3. 可复制配置:查询语句与参数修改片段
这一节是整篇的核心,所有内容都可以直接复制到你的环境里执行。我会先给出查询三个参数当前值的语句,再给出修改配置的片段,最后说明每个参数调整时需要注意的边界。
先看查询当前配置。在数据库客户端里执行:
show parameter open_cursors; show parameter sessions; show parameter processes;这三条语句会分别返回当前实例的配置值。如果你想一次性看到所有相关参数,可以用:
select name, value, description from v$parameter where name in ('open_cursors', 'sessions', 'processes', 'transactions') order by name;查询结果里,value 列就是当前生效的值。注意有些参数是静态参数,修改后需要重启实例才能生效,而 open_cursors 和 sessions 通常是动态参数,可以用 scope=both 在线修改。
接下来看当前实际使用情况。光看配置值不够,还要看实际消耗:
-- 查看当前会话数 select count(*) as current_sessions from v$session; -- 查看当前进程数 select count(*) as current_processes from v$process; -- 查看各会话打开的游标数,按数量降序 select s.sid, s.serial#, s.username, s.program, count(*) as cursor_count from v$open_cursor oc join v$session s on oc.sid = s.sid group by s.sid, s.serial#, s.username, s.program order by cursor_count desc;这三条语句分别对应 sessions、processes、open_cursors 的实际消耗。如果某条查询返回的数值已经逼近配置上限,那就是需要关注的对象。
修改参数的片段如下。先改 open_cursors:
alter system set open_cursors = 3000 scope=both;再改 sessions:
alter system set sessions = 3000 scope=both;processes 通常是静态参数,修改方式不同:
alter system set processes = 500 scope=spfile;注意 processes 改完后需要重启实例才生效。而且 processes 的值一般要大于 sessions,因为后台进程也要占名额。经验上 processes 大约是 sessions 的 1.1 到 1.5 倍。
如果你用的是配置文件方式管理,比如在 settings 文件里写死参数,可以参考这样的 JSON 结构:
{ "database": { "open_cursors": 3000, "sessions": 3000, "processes": 500 }, "connection_pool": { "max_pool_size": 200, "min_pool_size": 10, "connection_timeout": 30000 } }这个 JSON 只是示意结构,实际路径和字段名要根据你使用的框架来定。比如 Spring Boot 的 application.yml 里,连接池配置通常在spring.datasource.hikari下面。关键是 max_pool_size 不能超过 sessions 的值,否则连接池想开更多连接时会被数据库拒绝。
如果你用 TOML 格式管理配置,比如某些 CLI 工具的 settings 文件:
[database] open_cursors = 3000 sessions = 3000 processes = 500 [pool] max_size = 200 idle_timeout = 600同样,max_size 要小于 sessions。这个约束关系是排查时最容易忽略的点:连接池上限、sessions、processes 三者必须形成合理的梯度,否则调了数据库参数但应用侧还是报错。
配置改完之后,不要急着下结论,先执行验证请求,确认资源确实被回收了。下一节会给出具体的验证动作。
4. 验证请求与成功结果:确认资源真的回收了
改完参数只是第一步,真正要确认的是资源有没有被正确回收。很多连接泄漏的问题,改大参数只是把爆炸时间往后推,并没有解决根因。所以验证环节要分两步:先确认参数生效,再确认资源回收。
第一步,确认参数已经生效:
select name, value from v$parameter where name in ('open_cursors', 'sessions', 'processes');返回的 value 应该和你设置的值一致。如果 processes 还是旧值,说明实例没重启,静态参数没生效。
第二步,观察一段时间内的会话数变化。连续执行几次下面的查询,间隔几十秒:
select to_char(sysdate, 'HH24:MI:SS') as sample_time, count(*) as session_count from v$session;如果 session_count 在业务低峰期能回落到一个稳定值,说明连接池在正常释放连接。如果它只增不减,那就是连接泄漏的信号。
第三步,检查游标回收情况。执行:
select s.sid, s.username, s.program, count(*) as cursor_count from v$open_cursor oc join v$session s on oc.sid = s.sid group by s.sid, s.username, s.program having count(*) > 100 order by cursor_count desc;这条语句会列出游标数超过 100 的会话。正常情况下,单个会话的游标数应该在几十以内。如果某个会话的游标数持续在几百甚至上千,说明这个会话对应的应用代码没有正确关闭游标。
第四步,用实际请求验证。在你的应用里发起一次典型的数据库操作,比如查询、插入、更新各一次,然后立刻执行上面的游标查询。观察操作前后游标数的变化。如果操作完成后游标数没有回落,说明存在游标泄漏。
成功的结果应该是这样的:参数值符合预期,会话数在业务波动后能回落,游标数在操作完成后能释放,没有会话的游标数异常偏高。如果这四点都满足,说明资源回收是正常的。
如果验证过程中发现游标数不降,可以进一步定位是哪个 SQL 在堆积:
select sql_id, count(*) as cursor_count from v$open_cursor group by sql_id order by cursor_count desc fetch first 10 rows only;拿到 sql_id 之后,可以用select sql_text from v$sql where sql_id = '你的sql_id'查看具体语句。这样就能定位到是哪段代码在反复打开游标却不关闭。
验证通过之后,建议把观察到的基线值记录下来,比如正常情况下的会话数范围、游标数范围。后面再出现告警时,可以快速对比判断。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
排查过程中会遇到各种报错,有些是数据库本身的,有些是接入层或工具链的。这一节把常见的几类报错和对应动作列出来,方便你对照排查。
ORA-01000: maximum open cursors exceeded。这是最典型的游标超限报错。原因通常是 open_cursors 设置太小,或者应用没有关闭游标。动作:先查v$open_cursor找到游标数最高的会话和 SQL,确认是配置问题还是代码问题。如果是配置问题,按第 3 节的语句调大 open_cursors;如果是代码问题,去应用侧检查是否有未关闭的 ResultSet、Statement 或 Cursor。
ORA-00020: maximum number of processes exceeded。进程数打满。动作:查v$process确认当前进程数,查v$session确认会话数。如果 processes 接近上限,需要调大 processes 并重启实例。同时检查是否有大量空闲会话没有释放,连接池的 idle timeout 是否合理。
ORA-00018: maximum number of sessions exceeded。会话数超限。动作:查v$session按 username 和 program 分组统计,找出连接数异常的应用。检查连接池配置,确认 max_pool_size 是否超过 sessions。如果是连接泄漏,需要修复应用的连接关闭逻辑。
401 Unauthorized。这个报错通常出现在 API 接入层,不是数据库本身。原因一般是 API Key 填写错误、Key 过期、或者请求头里的鉴权字段格式不对。动作:检查配置文件里的 Key 是否和控制台创建的一致,确认请求头是Authorization: Bearer 你的Key格式。如果用的是 Claude Code 或类似工具,检查 settings 文件里的 apiKey 字段。
local proxy failed。这个报错一般出现在本地代理或网络层。动作:检查本地网络配置,确认 Base URL 填写正确。如果你用的是https://taotoken.net/api,确认没有多余的空格或换行。检查本地是否有其他服务占用了相同端口。
reading choices 相关报错。这类报错通常出现在调用模型接口时,返回结构解析失败。原因可能是 Model ID 填写错误,或者请求体格式不符合接口要求。动作:对照文档确认 Model ID 是否正确,检查请求体的 JSON 结构。如果是流式响应,确认客户端是否支持 SSE 解析。
OAuth 相关报错。如果工具链使用 OAuth 鉴权,报错可能是 token 过期或回调地址不匹配。动作:重新走一遍授权流程,确认回调地址和配置一致。如果用的是 API Key 方式,确认没有混用 OAuth 和 Key 两种鉴权模式。
Codex 的 auth.json 配置。如果你用 Codex 类工具,鉴权信息通常写在 auth.json 里。三件套要写全:
{ "base_url": "https://taotoken.net/api", "api_key": "你的API Key", "model": "你的Model ID" }这三个字段缺一不可。base_url 不带 UTM 参数,api_key 从控制台获取,model 按文档填写。如果 auth.json 里只写了 key 没写 base_url,请求会打到默认地址,导致 401 或连接失败。
Cline MCP 配置。如果你用 Cline 的 MCP 功能,配置里同样要写全 Base URL、Key、Model ID。MCP 的配置文件通常是 JSON 格式,路径根据工具不同而不同。确认这三个字段都在,并且 Base URL 指向https://taotoken.net/api。
CC Switch 配置。如果你用 CC Switch 管理多个配置,切换时要确认当前激活的配置里三件套完整。常见问题是切换后 Key 没跟着换,导致 401。
排查的核心思路是:先看报错类型,数据库报错查 v$ 视图,接入层报错查配置三件套。不要一上来就改参数,先定位是哪一层的问题。
6. 语义一致 CTA:把排查动作落到你的环境里
排查数据库连接层的资源占用,核心动作就是三步:查当前值、改配置、验证回收。这三步在本文里都有可复制的语句和片段,你可以直接拿到自己的环境里执行。
如果你在排查过程中需要辅助分析报错日志、生成查询语句、或者对比不同参数配置的行为,可以用 TaoToken 的模型对话能力:
https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite如果你需要长期做编码和 Agent 相关的排查工作,Coding Plan 提供了更稳定的调用方式:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite接入文档里有 Base URL、Model ID 和鉴权方式的完整说明:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewriteAPI Key 在控制台创建和管理:
https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewriteAPI Keys 管理入口:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite最后提醒一个实操细节:改完 open_cursors 和 sessions 之后,不要只看配置值,一定要用第 4 节的验证语句确认游标和会话真的在回收。参数调大只是给了缓冲空间,真正的资源回收还是要靠应用侧正确关闭连接和游标。把基线值记下来,下次告警时对比一下,就能快速判断是配置问题还是代码问题。