ARTICLE DETAIL

资讯详情

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

Oracle 11g 针对SQL性能的新特性(一)- Adaptive Cursor Sharing 实战拆解与 TaoToken 统一 Key 接入

Oracle 11g 针对SQL性能的新特性(一)- Adaptive Cursor Sharing 实战拆解与 TaoToken 统一 Key 接入 1. 从一次执行计划突变说起Oracle 11g Adaptive Cursor Sharing 到底解决了什么如果你维护过 Oracle 11g 的库大概率遇到过这种场景同一条带绑定变量的 SQL昨天跑 0.1 秒今天突然变成 8 秒执行计划从索引扫描变成了全表扫描而 SQL 文本一个字都没改。很多人第一反应是统计信息过期收集完统计信息发现还是老样子。这个现象背后往往就是绑定变量窥探Bind Peeking和执行计划共享之间的矛盾。Oracle 一直鼓励用绑定变量好处是减少硬解析、降低共享池压力、缩短解析时间。但绑定变量有个天然缺陷SQL 第一次执行时优化器会窥探一次绑定变量的实际值据此生成一个执行计划之后所有不同的绑定值都复用这个计划。对于等值查询这通常没问题但对于范围查询或者数据分布严重倾斜的列问题就大了。比如WHERE status :b如果第一次传入的是占比 1% 的稀有值优化器选索引扫描下次传入占比 60% 的常见值索引扫描就变成灾难。Oracle 曾经用CURSOR_SHARINGSIMILAR试图缓解结果带来更多解析和共享问题11.1 里就被废弃了。到了 11gAdaptive Cursor SharingACS登场它的思路是不再强制一条 SQL 只有一个计划而是让优化器根据绑定变量的实际选择率动态决定是复用旧计划还是生成新计划。简单说ACS 让游标在“共享”和“不共享”之间找到一个统计意义上的平衡点。这篇文章面向的是已经在用 Oracle 11g、被执行计划不稳定困扰的 DBA 和开发。我会先讲清楚 ACS 的触发条件和内部机制然后给出一套可复制的初始化参数配置和绑定变量测试脚本最后用数据倾斜场景演示如何通过V$SQL_CS_HISTOGRAM和V$SQL_CS_SELECTIVITY观察 ACS 的实时行为。同时因为现在很多团队在数据库之外还会用统一的 API 通道来调用模型做 SQL 审核、执行计划解读我也会顺带演示怎么用 TaoToken 的统一 Key 把这类分析请求接进来方便你把人工排查和自动化辅助串起来。ACS 不是银弹它有明确的适用边界和额外开销。理解它的触发条件比记住几个视图名字重要得多。下面从机制开始拆。2. TaoToken 统一 Key 接入把 SQL 分析请求收口到一个通道在深入 ACS 之前先花点篇幅说清楚 TaoToken 在这里扮演什么角色。你可能会问讲 Oracle 执行计划为什么要提 API 通道原因很实际排查 ACS 问题时我们经常需要把 SQL 文本、执行计划、V$SQL_CS_*视图的输出整理出来交给模型做模式识别或者生成对比报告。如果每个工具、每个脚本都各自维护一套 Key 和 Base URL时间一长就是一团乱麻。TaoToken 提供的是统一 Key 和统一 API 入口让你在多个客户端、多个脚本之间复用同一套凭证。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数保持干净。它的定位是统一的大模型 API 通道支持对话、编码计划、控制台管理、API Key 管理以及接入文档查询。对于做数据库运维的人来说比较实用的几个入口是模型对话用来快速问执行计划相关的问题比如“这个计划里 BUFFER SORT 出现在这里意味着什么”Coding Plan如果你在写 PL/SQL 或者 Python 脚本批量采集V$SQL数据可以用它辅助生成代码控制台管理你的 Key、查看用量API Keys生成和轮换密钥接入文档查具体的请求格式和参数我试过把 ACS 排查脚本的输出直接拼成 prompt通过统一 Key 发给模型让它对比两个 Child Cursor 的选择率范围差异。这样做的好处是你不需要在每台数据库服务器上配置不同的模型客户端只要网络能通到 API 入口用同一个 Key 就能跑。对于有多个环境开发、测试、生产的团队统一 Key 能省掉很多同步配置的麻烦。需要强调的是TaoToken 在这里是作为辅助分析通道存在的它不替代 SQLPlus、不替代 AWR、也不替代你直接查动态性能视图。ACS 的验证必须靠数据库自身的视图和真实执行模型只能帮你解读和归纳。把这两件事分清楚后面的操作才不会跑偏。接入时你需要的三件套是Base URLhttps://taotoken.net/api、API Key在控制台生成、Model ID按文档选。这三样在后面的配置片段里会具体出现。如果你只是想做本地 SQL 测试不接外部通道也完全没问题ACS 的验证步骤是独立的。3. 可复制配置初始化参数、测试表与绑定变量脚本这一节给出一套可以直接粘贴执行的配置和脚本。目标是在你的 11g 环境里构造出一个 bind sensitive 的 SQL并让它有机会触发 ACS。先确认你的版本SELECT * FROM v$version;本文描述基于 11.2.0.2 及以上、无额外补丁的环境。ACS 相关的隐藏参数和默认行为在不同小版本间有差异建议先在测试库验证。3.1 初始化参数与前提检查ACS 要工作有几个前提。第一CURSOR_SHARING必须是EXACT默认值SIMILAR已废弃且会干扰 ACS。第二优化器模式建议用ALL_ROWS。第三绑定变量窥探必须开启即_OPTIM_PEEK_USER_BINDS为 TRUE默认。检查语句-- 检查关键参数 SHOW PARAMETER cursor_sharing; SHOW PARAMETER optimizer_mode; SELECT nam.ksppinm, val.ksppstvl FROM sys.x$ksppi nam, sys.x$ksppcv val WHERE nam.inst_id val.inst_id AND nam.indx val.indx AND nam.ksppinm IN (_optim_peek_user_binds,_optimizer_adaptive_cursor_sharing);如果_optimizer_adaptive_cursor_sharing是 FALSEACS 整体关闭需要改成 TRUE需要重启或按文档方式调整。在测试环境可以这样设置ALTER SYSTEM SET _optimizer_adaptive_cursor_sharingTRUE SCOPESPFILE; -- 重启后生效生产环境改隐藏参数要谨慎先确认业务影响。cursor_sharing保持 EXACTALTER SYSTEM SET cursor_sharingEXACT SCOPEBOTH;3.2 构造数据倾斜的测试表ACS 的触发依赖数据分布不均。我们建一张订单表让status列严重倾斜99% 的行是 DONE1% 是 NEW。DROP TABLE t_acs_demo PURGE; CREATE TABLE t_acs_demo ( id NUMBER, status VARCHAR2(10), pad VARCHAR2(100) ); -- 插入 100 万行其中 99 万 DONE1 万 NEW INSERT /* APPEND */ INTO t_acs_demo SELECT level, CASE WHEN level 990000 THEN DONE ELSE NEW END, RPAD(x,100,x) FROM dual CONNECT BY level 1000000; COMMIT; -- 收集统计信息并生成直方图这是 bind sensitive 的关键 BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname USER, tabname T_ACS_DEMO, method_opt FOR ALL COLUMNS SIZE 254, cascade TRUE ); END; / -- 确认直方图存在 SELECT column_name, histogram, num_buckets FROM user_tab_col_statistics WHERE table_name T_ACS_DEMO;status列应该有 FREQUENCY 或 HEIGHT BALANCED 直方图。没有直方图等值查询不会成为 bind sensitiveACS 也就无从触发。3.3 绑定变量测试脚本下面这段脚本用同一个游标先传稀有值 NEW再传常见值 DONE反复执行观察 Child Cursor 的变化。注意每次执行后查V$SQL的IS_BIND_SENSITIVE、IS_BIND_AWARE、IS_SHAREABLE。-- 清理环境 ALTER SYSTEM FLUSH SHARED_POOL; VARIABLE b_status VARCHAR2(10); -- 第一次执行传入稀有值 NEW EXEC :b_status : NEW; SELECT COUNT(*) FROM t_acs_demo WHERE status :b_status; -- 查看游标状态 SELECT sql_id, child_number, is_bind_sensitive, is_bind_aware, is_shareable, executions FROM v$sql WHERE sql_text LIKE %t_acs_demo%status :b_status%; -- 第二次执行传入常见值 DONE EXEC :b_status : DONE; SELECT COUNT(*) FROM t_acs_demo WHERE status :b_status; -- 再次查看此时 Child 0 的 histogram 应该出现两个 bucket 都有计数 SELECT sql_id, child_number, is_bind_sensitive, is_bind_aware, is_shareable, executions FROM v$sql WHERE sql_text LIKE %t_acs_demo%status :b_status%; -- 第三次执行再传 DONE触发 ACS 生成新 Child EXEC :b_status : DONE; SELECT COUNT(*) FROM t_acs_demo WHERE status :b_status; -- 观察 Child 数量变化 SELECT sql_id, child_number, is_bind_sensitive, is_bind_aware, is_shareable, executions FROM v$sql WHERE sql_text LIKE %t_acs_demo%status :b_status% ORDER BY child_number;执行到第三次左右你应该能看到IS_BIND_AWARE从 N 变成 Y并且出现 child_number 大于 0 的新游标。这就是 ACS 被触发的标志。如果一直是 N检查直方图是否存在、_optimizer_adaptive_cursor_sharing是否为 TRUE、以及是否执行了足够次数至少两次以上。3.4 通过 TaoToken 统一 Key 接入分析请求的配置片段如果你想把上面的查询结果自动整理后发给模型做解读可以用下面这个 JSON 配置。它把 Base URL、Key、Model ID 三件套集中管理避免散落在各个脚本里。{ provider: taotoken, base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key-here, model_id: your-selected-model-id, timeout_seconds: 60, headers: { Content-Type: application/json }, endpoints: { chat: /v1/chat/completions, models: /v1/models } }对应的 TOML 形式方便你在 Python 或 CLI 工具里读取[taotoken] base_url https://taotoken.net/api api_key sk-your-taotoken-key-here model_id your-selected-model-id timeout_seconds 60 [taotoken.endpoints] chat /v1/chat/completions models /v1/modelsKey 在控制台生成Model ID 按接入文档里的列表选。把这段配置放在你的采集脚本旁边脚本负责查V$SQL_CS_HISTOGRAM配置负责发请求职责清晰。注意不要把 Key 硬编码进 SQL 脚本或者提交到版本库。4. 验证请求与成功结果观察 V$SQL_CS_HISTOGRAM 与 V$SQL_CS_SELECTIVITY配置和脚本跑起来之后关键在验证。ACS 的行为全部记录在几个V$SQL_CS_*视图里其中V$SQL_CS_HISTOGRAM和V$SQL_CS_SELECTIVITY是最直接的两个。前者按行数分桶记录每个 Child 的执行次数后者记录每个 Child 对应的绑定变量选择率范围。4.1 查询 V$SQL_CS_HISTOGRAM先拿到 sql_idSELECT sql_id, child_number, is_bind_sensitive, is_bind_aware, is_shareable FROM v$sql WHERE sql_text LIKE %t_acs_demo%status :b_status% ORDER BY child_number;假设 sql_id 是abc123xyz查直方图SELECT sql_id, child_number, bucket_id, count FROM v$sql_cs_histogram WHERE sql_id abc123xyz ORDER BY child_number, bucket_id;bucket_id 的含义是0 表示处理行数小于 1K1 表示 1K 到 1M 之间2 表示大于 1M。当 Child 0 在 bucket 0 和 bucket 2 上都有非零计数时说明同一个计划在不同绑定值下处理的行数差异巨大这正是 ACS 要介入的信号。你会看到类似这样的输出SQL_IDCHILD_NUMBERBUCKET_IDCOUNTabc123xyz001abc123xyz022abc123xyz101abc123xyz121Child 0 在 bucket 0 和 bucket 2 都有计数触发了 ACSChild 1 是 bind aware 之后生成的新游标它针对特定选择率范围服务。4.2 查询 V$SQL_CS_SELECTIVITY这个视图告诉你每个 Child 负责的选择率区间SELECT sql_id, child_number, range_id, low, high FROM v$sql_cs_selectivity WHERE sql_id abc123xyz ORDER BY child_number, range_id;输出示例SQL_IDCHILD_NUMBERRANGE_IDLOWHIGHabc123xyz100.0000010.000100abc123xyz110.9000001.000000这表示 Child 1 覆盖了两个选择率区间极低选择率稀有值和极高选择率常见值。后续执行时优化器先算本次绑定变量的选择率落在哪个区间就用哪个 Child 的计划。如果都不在就生成新计划、新 Child。4.3 结合执行计划对比光看视图还不够要确认不同 Child 真的用了不同计划SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(abc123xyz, 0, ALLSTATS LAST)); SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(abc123xyz, 1, ALLSTATS LAST));Child 0 大概率是索引扫描针对稀有值Child 1 可能是全表扫描或不同的连接方式针对常见值。如果两个 Child 的计划完全一样说明 ACS 虽然生成了新游标但优化器判断不需要换计划这也是正常情况。4.4 通过统一 Key 发送验证请求把上面的查询结果整理成文本通过 TaoToken 的对话接口发出去让模型帮你归纳两个 Child 的选择率差异。请求体大致如下{ model: your-selected-model-id, messages: [ { role: user, content: 以下是 Oracle 11g ACS 的两个 Child Cursor 的选择率范围和直方图数据请分析哪个 Child 服务稀有值、哪个服务常见值并指出是否存在计划切换风险。数据Child 0 histogram bucket01,bucket22; Child 1 selectivity range00.000001-0.000100, range10.9-1.0。 } ], temperature: 0.2 }发送到https://taotoken.net/api/v1/chat/completions带上Authorization: Bearer sk-your-taotoken-key-here。返回结果会给你一个结构化的解读省去自己对着数字推敲的时间。这一步不是必须的但如果你要批量处理几十条 SQL 的 ACS 状态自动化解读会明显提效。验证成功的标准是V$SQL里出现IS_BIND_AWAREY的 ChildV$SQL_CS_HISTOGRAM里 Child 0 至少两个 bucket 有计数V$SQL_CS_SELECTIVITY里新 Child 有明确的选择率区间。三者同时满足说明 ACS 在你的环境里正常工作。5. 本篇常见报错排查401、local proxy failed、reading choices 与 OAuth这一节集中处理两类问题一类是 ACS 本身不触发另一类是接入 TaoToken 统一 Key 时遇到的请求错误。两类问题经常混在一起因为排查 ACS 的脚本可能同时要发 API 请求报错信息容易让人误判方向。5.1 ACS 不触发IS_BIND_AWARE 一直是 N最常见的原因是直方图缺失。等值查询要成为 bind sensitive列上必须有直方图。检查SELECT column_name, histogram, num_buckets FROM user_tab_col_statistics WHERE table_name T_ACS_DEMO AND column_name STATUS;如果 histogram 是 NONE重新收集统计信息method_opt用FOR COLUMNS STATUS SIZE 254。第二个原因是执行次数不够ACS 需要至少两次执行、且 Child 0 的直方图出现两个 bucket 同高才触发。第三个原因是_optimizer_adaptive_cursor_sharing被关掉了用第 3 节的隐藏参数查询确认。第四个原因是CURSOR_SHARING被设成了FORCE或SIMILAR改回EXACT。5.2 401 Unauthorized这是接入 TaoToken 时最直接的错误。原因通常是 Key 缺失、拼写错误、或者请求头格式不对。检查你的请求头Authorization: Bearer sk-your-taotoken-key-here注意Bearer和 Key 之间有一个空格Key 不要带多余引号。如果你用的是 JSON 配置文件确认api_key字段没有被环境变量覆盖成空值。401 和 ACS 无关纯粹是凭证问题。在控制台重新生成一个 Key 试试排除 Key 被禁用或过期的可能。5.3 local proxy failed这个报错通常出现在你的脚本或客户端配置了本地代理但代理进程没起来或者端口不对。TaoToken 的 API 入口是https://taotoken.net/api如果你的环境里设置了HTTP_PROXY或HTTPS_PROXY环境变量而代理不可用就会报 local proxy failed。检查echo $HTTP_PROXY echo $HTTPS_PROXY如果不需要代理清空这两个变量再跑。如果需要确认代理地址和端口正确。这个错误和数据库无关是网络层配置问题。5.4 reading choices 相关报错这类报错一般出现在解析模型返回结果时比如你期望返回 JSON但实际拿到的是流式文本或者错误页。检查两点一是请求的Content-Type是否为application/json二是响应状态码是否为 200。如果返回体里包含choices字段但你的解析代码没处理就会报 reading choices 失败。建议先把原始响应打印出来看结构再写解析逻辑。Model ID 填错也可能导致返回非预期结构按接入文档核对。5.5 OAuth 相关错误如果你用的是需要 OAuth 流程的客户端报错可能指向 token 获取失败。TaoToken 的 API Key 方式是直接 Bearer Token不涉及 OAuth 跳转。如果你在某个工具里看到 OAuth 报错先确认该工具是否支持 API Key 直连模式。把认证方式从 OAuth 切换到 API Key填入 Base URL 和 Key 即可。三件套Base URL、Key、Model ID缺一不可任何一项不对都会导致认证或路由失败。5.6 排查顺序建议遇到问题先分层数据库层的问题查V$SQL、V$SQL_CS_*、直方图网络层的问题查代理、DNS、连通性认证层的问题查 Key、请求头、Model ID。不要一看到报错就改数据库参数也不要一看到 ACS 不触发就去换 API Key。分层排查能省很多时间。6. 把 ACS 验证和统一 Key 接入串成日常流程ACS 的价值在于它让优化器对绑定变量的选择率有了“记忆”和“分诊”能力但它的触发条件比较苛刻需要直方图、需要多次执行、需要数据倾斜。实际生产里不是每条 SQL 都会走 ACS你也不需要监控所有 SQL。比较务实的做法是先找出那些IS_BIND_SENSITIVEY且执行频繁的游标重点观察它们的V$SQL_CS_HISTOGRAM是否出现多 bucket 同高再决定是否深入。日常流程可以这样组织用一段 PL/SQL 或 Python 脚本定期采集V$SQL里 bind sensitive 的游标把 sql_id、child_number、histogram、selectivity 导出然后通过 TaoToken 的统一 Key 把整理后的数据发给模型生成一份变化摘要比如“本周新增 3 个 bind aware 游标其中 2 个的选择率区间重叠存在计划切换风险”。这样你不需要人工盯每个视图只需要看摘要。采集脚本里读取配置的部分用第 3 节的 JSON 或 TOML 片段把 Base URL 固定为https://taotoken.net/apiKey 从环境变量注入Model ID 按文档选。这样换环境时只改环境变量不动脚本。如果你在写批量采集的 Python 代码可以用 Coding Plan 辅助生成模板减少重复劳动。最后提醒一点ACS 会带来额外的硬解析和 Child Cursor共享池压力会上升。在 11g 上如果你的共享池本来就紧张ACS 触发后可能引发ORA-04031。所以验证 ACS 的同时也要关注V$SHARED_POOL_ADVICE和V$SQL_SHARED_CURSOR里的不可共享原因。把 ACS 当成一个需要调优的特性而不是开了就完事的开关。如果你想把执行计划解读这一步也自动化可以从模型对话入口进去把DBMS_XPLAN的输出贴进去让它标出可能的瓶颈算子。接入文档里有具体的请求示例照着改 Base URL 和 Key 就行。整套流程跑通后你手里就有了一条从数据库视图采集、到统一 Key 转发、再到模型解读的链路排查 ACS 问题时不用再在多个工具之间来回切换。
返回列表