ARTICLE DETAIL

资讯详情

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

SQL调优指南笔记19:Influencing the Optimizer——把初始化参数改到 TaoToken 的实践路径

SQL调优指南笔记19:Influencing the Optimizer——把初始化参数改到 TaoToken 的实践路径 1. 从一次执行计划突变说起Oracle 优化器到底被谁影响了如果你做过 Oracle SQL 调优大概率遇到过这种场景同一条 SQL昨天跑 0.3 秒今天突然变成 8 秒执行计划从 INDEX RANGE SCAN 变成了 TABLE ACCESS FULL。你翻遍 SQL 文本没改过统计信息也没动最后发现是某个初始化参数在实例级别被调整了或者某个 Hint 因为查询块被合并而失效了。这就是 SQL Tuning Guide 第 19 章 Influencing the Optimizer 要解决的核心问题优化器默认值适用于大多数操作但不是全部。当你有优化器不知道的信息或者需要针对特定语句、特定工作负载调整优化器行为时就需要主动影响它。影响优化器的手段主要有四类初始化参数、Hints、DBMS_STATS 统计信息、SQL 配置文件与 SQL 计划管理。其中初始化参数作用于实例和会话级别影响面最广Hints 作用于单条语句控制粒度最细。两者经常配合使用比如 SQL 计划管理内部就同时用到了参数和 Hints。我在实际排查中总结出一条经验先看参数再看 Hint最后看统计信息。因为参数是全局的一旦设错影响所有 SQLHint 是局部的但容易被查询转换吃掉统计信息是基础但更新周期长。本文会沿着这条排查链路把初始化参数和 Hints 的机制讲清楚并给出可复制的配置片段和验证方法。另外调优过程中经常需要把执行计划、Hint 报告、参数快照这些信息汇总分析。我习惯把这些诊断数据通过统一的 API 通道做结构化处理后面会演示怎么把 Base URL 指向 TaoToken 统一通道让调优脚本的模型调用和诊断输出走同一条路径方便对比不同参数下的计划稳定性。适合阅读本文的人已经会看 EXPLAIN PLAN、知道什么是驱动表、但被Hint 写了不生效参数改了没反应困扰的 DBA 和开发。全文按问题场景 → 前置准备 → 可复制配置 → 验证请求 → 错排查 → 工具入口展开每一步都能直接跟做。2. 影响优化器的初始化参数与 Hints 机制拆解2.1 驱动表与连接顺序优化器决策的起点在讲参数之前先把一个基本概念钉死驱动表driving table是其他表连接到的表也叫外表outer table。用编程类比就是一个嵌套 for 循环里外层的那个循环。驱动表通常包含能消除最高百分比行的过滤条件。连接顺序对性能影响巨大。准则有三条当索引能更有效检索行时避免全表扫描当能用获取少量行的不同索引时避免使用从驱动表获取多行的索引选择连接顺序让更少的行在连接顺序后期才连入表中。看一个典型例子SELECT * FROM taba a, tabb b, tabc c WHERE a.acol BETWEEN 100 AND 200 AND b.bcol BETWEEN 10000 AND 20000 AND c.ccol BETWEEN 10000 AND 20000 AND a.key1 b.key1 AND a.key2 c.key2;前三个条件是单表过滤条件后两个是连接条件。因为 acol 的范围 100 到 200 较窄而 bcol、ccol 的范围 10000 到 20000 较大所以 taba 是驱动表。如果 bcol 的过滤比 ccol 更具限制性拒绝更高百分比的行那么 tabb 应该在 tabc 之前连接这样最后一个连接处理的行数更少。你可以用 ORDERED 或 STAR 提示强制连接顺序。但要注意强制连接顺序是一把双刃剑数据分布变化后可能适得其反。2.2 关键初始化参数逐个说清Oracle 提供了一批初始化参数来影响优化器行为。下面这张表是我按调优时最常动的顺序整理的重点参数会展开讲。参数作用调优时的注意点OPTIMIZER_MODE设置优化器目标ALL_ROWS 求吞吐FIRST_ROWS_n 求响应OPTIMIZER_FEATURES_ENABLE控制优化器特性集升级后保留旧行为但官方不建议长期设旧版本OPTIMIZER_ADAPTIVE_PLANS控制自适应计划默认 TRUE测试时可关OPTIMIZER_ADAPTIVE_REPORTING_ONLY自适应仅报告模式设为 TRUE 只收集信息不改计划OPTIMIZER_ADAPTIVE_STATISTICS控制自适应统计默认 FALSE涉及计划指令、统计反馈、动态采样OPTIMIZER_INDEX_CACHING嵌套循环索引探测成本0 到 100表示索引块在缓冲区缓存的百分比OPTIMIZER_INDEX_COST_ADJ调整索引探测成本1 到 10000默认 100DB_FILE_MULTIBLOCK_READ_COUNT全表扫描单次 I/O 块数值大则全表扫描成本低可能放弃索引CURSOR_SHARING字面量转绑定变量FORCE 改善游标共享但影响计划QUERY_REWRITE_ENABLED查询重写开关TRUE/FALSE/FORCE涉及物化视图RESULT_CACHE_MODE结果缓存模式MANUAL 默认FORCE 全缓存有正确性风险OPTIMIZER_INMEMORY_AWARE内存列存储成本模型设 FALSE 则忽略 INMEMORY 属性OPTIMIZER_MODE 是最常动的。批处理应用如 Oracle Reports优化吞吐量设 ALL_ROWS交互式应用如 Oracle Forms、SQL*Plus优化响应时间设 FIRST_ROWS_nn 取 1、10、100 或 1000。你可以在实例级别设一个在会话级别覆盖-- 实例级别针对响应时间 ALTER SYSTEM SET OPTIMIZER_MODEFIRST_ROWS_10; -- 当前会话跑报表改回吞吐量 ALTER SESSION SET OPTIMIZER_MODEALL_ROWS;OPTIMIZER_FEATURES_ENABLE 要特别小心。它接受版本号字符串比如 11.2.0.2 或 12.2.0.1。升级数据库后这个参数的默认值会跟着变可能导致执行计划改变。官方明确警告不建议显式设置为早期版本为避免计划变化导致性能下降应改用 SQL 计划管理。SHOW PARAMETER optimizer_features_enable -- 输出optimizer_features_enable string 12.2.0.1 ALTER SYSTEM SET OPTIMIZER_FEATURES_ENABLE12.1.0.2;自适应优化这块启用自适应计划需要三个条件同时满足OPTIMIZER_ADAPTIVE_PLANS 为 TRUE默认、OPTIMIZER_FEATURES_ENABLE 为 12.1.0.1 或更高、OPTIMIZER_ADAPTIVE_REPORTING_ONLY 为 FALSE默认。如果只想收集信息不改计划把 REPORTING_ONLY 设为 TRUEALTER SESSION SET OPTIMIZER_ADAPTIVE_REPORTING_ONLYtrue; -- 然后用 REPORT 参数运行 DBMS_XPLAN.DISPLAY_CURSOR2.3 Hints 的语法、类型与作用域Hint 是嵌入在 SQL 注释中的指令必须紧跟语句块的第一个关键字。注释定界符后必须紧跟加号加号前不允许有空格SELECT /* hint_text */ ...一个语句块只能有一个包含 Hint 的注释但可以包含多个空格分隔的 HintSELECT /* FULL(hr_emp) CACHE(hr_emp) */ last_name FROM employees hr_emp;Hint 分四类单表提示如 INDEX、USE_NL、多表提示如 LEADING、查询块提示如 STAR_TRANSFORMATION、UNNEST、语句提示如 ALL_ROWS。作用域上Hint 会覆盖实例级或会话级参数。-- 单表提示 SELECT /* INDEX (employees emp_department_ix) */ employee_id, department_id FROM employees WHERE department_id 50; -- 多表提示 SELECT /* LEADING(e j) */ * FROM employees e, departments d, job_history j WHERE e.department_id d.department_id AND e.hire_date j.start_date; -- 查询块提示 SELECT /* INDEX(t1) FULL(sel$2 t1) */ COUNT(*) FROM jobs t1 WHERE t1.job_id IN (SELECT job_id FROM employees t1); -- 语句提示 SELECT /* ALL_ROWS */ * FROM sales;Hint 的缺点是管理、检查和控制的额外代码。数据库和主机环境的变化可能让 Hint 过时甚至产生负面影响。所以好的做法是用 Hint 做测试用其他技术管理执行计划。Oracle 提供了 SQL Tuning Advisor、SQL 计划管理、SQL 性能分析器等工具官方强烈建议优先用这些工具而不是 Hint。2.4 Hint 使用报告为什么你的 Hint 没生效Oracle 19c 之前很难确定优化器为什么不使用 Hint。Hint 使用报告解决了这个问题。数据库不会对忽略的 Hint 报错但报告会显示哪些 Hint 被使用、哪些被忽略以及忽略原因。忽略 Hint 的常见原因有四类语法错误拼写错误或无效参数、未解决的 Hint语法没错但无效比如索引名不存在、相互矛盾的 Hint如同时 FULL 和 INDEX、受变换影响的 Hint查询转换让某些 Hint 失效。访问报告的方式是在 DBMS_XPLAN 函数的 format 参数中指定 HINT_REPORT。TYPICAL 只显示未使用的 HintALL 显示已使用和未使用的。EXPLAIN PLAN FOR SELECT /* INDEX(e emp_emp_id_pk) */ COUNT(*) FROM employees e WHERE e.employee_id 5; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format ALL));报告里 U 表示未使用N 表示未解决E 表示语法错误。比如U - FULL(t1) / hint overridden by another in parent query block说明这个 Hint 被父查询块中的另一个 Hint 覆盖了。3. 可复制的参数配置与 Hint 写法片段3.1 会话级参数配置模板调优时我习惯先建一个会话级配置脚本把要测试的参数集中设置方便回滚。下面这个片段可以直接复制到 SQL*Plus 或 SQLcl 里执行-- 保存当前会话参数快照便于对比 SELECT name, value FROM v$parameter WHERE name IN (optimizer_mode,optimizer_features_enable, optimizer_adaptive_plans,optimizer_adaptive_reporting_only, optimizer_index_caching,optimizer_index_cost_adj, db_file_multiblock_read_count,cursor_sharing) ORDER BY name; -- 会话级调整交互式场景求响应时间 ALTER SESSION SET OPTIMIZER_MODEFIRST_ROWS_10; -- 测试自适应计划时只报告不改计划 ALTER SESSION SET OPTIMIZER_ADAPTIVE_REPORTING_ONLYtrue; -- 调整索引探测成本假设 ALTER SESSION SET OPTIMIZER_INDEX_CACHING90; ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ10;这里 OPTIMIZER_INDEX_CACHING 设 90 表示假设 90% 的索引块能在缓冲区缓存中找到优化器会相应调低嵌套循环的成本。OPTIMIZER_INDEX_COST_ADJ 设 10 表示索引访问路径成本是正常成本的十分之一。这两个参数要谨慎设错会让执行计划偏向索引反而变慢。3.2 实例级参数配置需谨慎实例级参数影响所有会话改之前一定要在测试库验证。下面用 ALTER SYSTEM 配合 SCOPE 控制生效范围-- 仅当前实例生效重启后失效适合临时验证 ALTER SYSTEM SET OPTIMIZER_ADAPTIVE_PLANSfalse SCOPEMEMORY; -- 持久化到 spfile重启后仍生效 ALTER SYSTEM SET DB_FILE_MULTIBLOCK_READ_COUNT128 SCOPEBOTH; -- 查看修改后的值 SHOW PARAMETER optimizer_adaptive_plans; SHOW PARAMETER db_file_multiblock_read_count;DB_FILE_MULTIBLOCK_READ_COUNT 以块为单位默认值对应数据库能有效执行的最大 I/O 大小多数平台 1MB。如果会话数非常大多块读取计数值会减小避免缓冲区缓存被太多表扫描缓冲区淹没。设大这个值会降低全表扫描成本可能让优化器放弃索引。3.3 Hint 写法与连接顺序控制连接顺序 Hint 的准则是选择驱动表和驱动索引让过滤条件消除最高百分比的行选择连接顺序尽早找到最好的未使用过滤器。-- 强制连接顺序taba 驱动然后 tabb最后 tabc SELECT /* ORDERED USE_NL(b) USE_NL(c) INDEX(a idx_a) INDEX(b idx_b) */ a.acol, b.bcol, c.ccol FROM taba a, tabb b, tabc c WHERE a.acol BETWEEN 100 AND 200 AND b.bcol BETWEEN 10000 AND 20000 AND c.ccol BETWEEN 10000 AND 20000 AND a.key1 b.key1 AND a.key2 c.key2; -- 星型转换提示 SELECT /* STAR_TRANSFORMATION */ * FROM sales s, times t, products p WHERE s.time_id t.time_id AND s.prod_id p.prod_id; -- 查询块级 Hint指定只对某个查询块生效 SELECT /* INDEX(t1) FULL(sel$2 t1) */ COUNT(*) FROM jobs t1 WHERE t1.job_id IN (SELECT /* FULL(t1) */ job_id FROM employees t1);3.4 把诊断脚本的 Base URL 指向 TaoToken 统一通道调优过程中我经常需要把执行计划、Hint 报告、参数快照这些文本做结构化对比或者让模型帮忙分析计划差异。这时候如果每个脚本各自配置不同的 API 地址维护起来很乱。我的做法是把 Base URL 统一指向 TaoToken 通道让所有诊断脚本走同一条路径。下面是一个 Python 诊断脚本的配置片段把模型调用的 Base URL 和 Key 集中管理import os import json import requests # 统一通道配置Base URL 指向 TaoTokenKey 从环境变量读取 TAOTOKEN_BASE_URL https://taotoken.net/api TAOTOKEN_API_KEY os.environ.get(TAOTOKEN_API_KEY, ) # 模型 ID 按需选择调优分析用长上下文模型 MODEL_ID claude-sonnet-4-20250514 def analyze_plan(plan_text: str) - str: 把执行计划和 Hint 报告发给模型做差异分析 headers { Authorization: fBearer {TAOTOKEN_API_KEY}, Content-Type: application/json, } payload { model: MODEL_ID, messages: [ {role: system, content: 你是 Oracle 执行计划分析助手只输出计划差异和可能原因。}, {role: user, content: f分析以下执行计划指出访问路径和连接方式的变化\n{plan_text}}, ], max_tokens: 2048, } resp requests.post( f{TAOTOKEN_BASE_URL}/v1/messages, headersheaders, datajson.dumps(payload), timeout60, ) resp.raise_for_status() return resp.json()[content][0][text] if __name__ __main__: sample_plan | Id | Operation | Name | Rows | Cost | | 0 | SELECT STATEMENT | | 1 | 4 | | 1 | SORT AGGREGATE | | 1 | | | 2 | INDEX UNIQUE SCAN| EMP_EMP_ID_PK| 1 | 0 | print(analyze_plan(sample_plan))这段代码里 Base URL 是https://taotoken.net/apiKey 通过环境变量注入模型 ID 显式指定。三件套Base URL Key Model ID齐全换模型只改 MODEL_ID 一行。如果你用的是 Claude Code 或 Cline 这类工具配置方式类似把 Base URL 填到对应设置里即可。4. 验证请求与成功结果确认优化器选择真的变了4.1 用 EXPLAIN PLAN 和 DBMS_XPLAN 验证改完参数或加了 Hint第一步是看执行计划有没有变。用 EXPLAIN PLAN 加 DBMS_XPLAN.DISPLAY 是最直接的方式EXPLAIN PLAN FOR SELECT /* INDEX(e emp_emp_id_pk) */ COUNT(*) FROM employees e WHERE e.employee_id 5; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format ALL));成功输出里会包含 Hint Report 段显示 Hint 的使用状态Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 1 --------------------------------------------------------------------------- 2 - SEL$1 / ESEL$1 - INDEX(e emp_emp_id_pk)这里没有 U 前缀说明 INDEX 提示被使用了。计划行号 2 对应表 ESEL$1 在计划表中首次出现的行。4.2 用 DBMS_XPLAN.DISPLAY_CURSOR 看真实执行EXPLAIN PLAN 是预估要看真实执行情况得用 DISPLAY_CURSOR。先执行 SQL再查游标-- 执行目标 SQL SELECT /* INDEX(t1) FULL(sel$2 t1) */ COUNT(*) FROM jobs t1 WHERE t1.job_id IN (SELECT /* FULL(t1) */ job_id FROM employees t1); -- 查看真实执行计划和 Hint 报告 SET PAGES 9999 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format ALL));成功输出会显示 SQL_ID、child number、Plan hash value以及完整的 Hint Report。比如下面这种报告说明有一个 Hint 未使用Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 3 (U - Unused (1)) --------------------------------------------------------------------------- 4 - SEL$5DA710D3 / T1SEL$2 U - FULL(t1) / hint overridden by another in parent query block - FULL(sel$2 t1) 5 - SEL$5DA710D3 / T1SEL$1 - INDEX(t1)U 表示未使用原因是被父查询块中的另一个 Hint 覆盖。这说明 FULL(sel$2 t1) 生效了而子查询块里的 FULL(t1) 被覆盖。4.3 参数调整前后的计划对比验证参数是否生效最可靠的方法是做前后对比。下面这个脚本把调整前后的计划哈希和关键操作记录下来-- 调整前 ALTER SESSION SET OPTIMIZER_MODEALL_ROWS; EXPLAIN PLAN SET STATEMENT_IDBEFORE FOR SELECT * FROM employees e, departments d WHERE e.department_id d.department_id AND e.salary 10000; -- 调整后 ALTER SESSION SET OPTIMIZER_MODEFIRST_ROWS_10; EXPLAIN PLAN SET STATEMENT_IDAFTER FOR SELECT * FROM employees e, departments d WHERE e.department_id d.department_id AND e.salary 10000; -- 对比两次计划 SELECT statement_id, operation, options, object_name, cost FROM plan_table WHERE statement_id IN (BEFORE,AFTER) ORDER BY statement_id, id;成功结果会显示两次计划的 operation 和 cost 差异。如果 FIRST_ROWS_10 生效通常会看到 NESTED LOOPS 替代 HASH JOIN因为嵌套循环更适合快速返回前几行。4.4 通过统一通道验证模型分析结果把执行计划文本发给模型分析时成功返回的 JSON 结构如下{ id: msg_01XyZ..., type: message, role: assistant, content: [ { type: text, text: 计划从 HASH JOIN 变为 NESTED LOOPS驱动表为 EMPLOYEES索引 EMP_DEPARTMENT_IX 被使用。成本从 12 降到 4符合 FIRST_ROWS_10 的响应时间目标。 } ], model: claude-sonnet-4-20250514, stop_reason: end_turn }如果返回 401说明 Key 没配好如果返回 404检查 Base URL 路径是否正确。这些错误在下一节详细说。5. 本篇常见错排查401、Hint 不生效、计划没变5.1 401 UnauthorizedKey 没传或传错调用统一通道时最常见的错误是 401。原因通常是环境变量没设置或者 Key 带了多余空格。排查步骤# 检查环境变量是否设置 echo $TAOTOKEN_API_KEY # 如果为空重新导出注意不要有多余空格和换行 export TAOTOKEN_API_KEY你的Key # 用 curl 快速验证 curl -s -o /dev/null -w %{http_code} \ -X POST https://taotoken.net/api/v1/messages \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,max_tokens:16,messages:[{role:user,content:hi}]}返回 200 说明 Key 和 Base URL 都对。返回 401 就检查 Key 是否过期或复制时多了空格。5.2 local proxy failed本地代理配置冲突如果你在本地设置了 HTTP_PROXY 或 HTTPS_PROXY请求可能被转发到不可用的代理报local proxy failed或连接超时。排查# 查看当前代理设置 env | grep -i proxy # 临时清空代理再试 unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy在 Python 脚本里可以显式禁用代理proxies {http: None, https: None} resp requests.post(url, headersheaders, datapayload, proxiesproxies, timeout60)5.3 reading choices响应结构解析错误有些兼容接口返回的结构和预期不一致解析choices字段时报KeyError: choices或reading choices failed。原因是不同接口的响应格式不同有的返回content[0].text有的返回choices[0].message.content。排查方法是先打印原始响应resp requests.post(url, headersheaders, datapayload, timeout60) print(resp.status_code) print(resp.text[:500]) # 先看原始结构再解析确认结构后再写解析逻辑。如果用的是 Anthropic 风格接口取content[0].text如果是 OpenAI 风格取choices[0].message.content。5.4 OAuth token 过期认证方式不匹配如果你用的是 OAuth 方式认证token 过期会报OAuth token expired或invalid_grant。排查# 检查 token 有效期如果是 JWT echo $TAOTOKEN_API_KEY | cut -d. -f2 | base64 -d 2/dev/null | python -m json.tool如果确认过期重新获取 token。对于长期运行的调优脚本建议用 API Key 而不是 OAuth token避免中途失效。5.5 Hint 写了不生效四类原因对照回到 Oracle 本身Hint 不生效的排查要对照 Hint Report。下面这张表把报告标记和原因对应起来报告标记含义常见原因处理方式E语法错误拼写错误、无效参数检查 Hint 拼写和参数N未解决索引名不存在、查询块不存在确认对象名和查询块名U未使用被覆盖、冲突、受变换影响看报告里的具体说明无标记已使用正常生效无需处理比如U - INDEX_RS(e emp_manager_ix)未使用原因是索引不对应该是 JOB 而非 MANAGER 上的索引。再比如U - INDEX_FFS(e) / hint conflicts with another in sibling query block说明 INDEX_FFS 和 INDEX_SS 冲突索引快速全扫描和索引跳过扫描互斥优化器忽略了两个 Hint。5.6 参数改了计划没变检查作用域和优先级参数改了但计划没变常见原因有三个一是改的是实例级但当前会话有覆盖二是参数被 Hint 覆盖Hint 优先级高于参数三是参数本身不直接影响该 SQL 的决策路径。排查顺序先SHOW PARAMETER确认当前会话的实际值再用ALTER SESSION显式设置最后看 Hint Report 确认没有 Hint 覆盖。记住优先级Hint 会话级参数 实例级参数。6. 把调优链路接到 TaoToken入口与后续步骤调优做到后面你会发现真正花时间的不是改参数而是对比不同参数组合下的计划差异、整理 Hint 报告、把诊断结论沉淀成可复用的脚本。这些工作如果靠手工复制粘贴很容易出错。我的做法是把诊断脚本的模型调用统一走 TaoToken 通道Base URL 固定为https://taotoken.net/apiKey 和 Model ID 集中管理。这样换模型、换分析策略时只改一处配置执行计划对比、Hint 报告解读、参数快照分析都能走同一条链路。如果你刚开始接触建议按这个顺序推进先在模型对话里验证通道连通性确认 Base URL 和 Key 配置正确然后到接入文档对照接口格式把诊断脚本的请求结构调通接着在 API Keys 页面管理你的 Key给不同脚本分配不同 Key 便于追踪最后如果要做长期的编码和 Agent 任务可以了解 Coding Plan 的用法。具体入口模型对话验证连通https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentsql_tuning_optimizer接入文档对照接口https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentsql_tuning_optimizerAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentsql_tuning_optimizerCoding Plan 长期任务https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentsql_tuning_optimizer控制台总览https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentsql_tuning_optimizer回到 Oracle 调优本身最后给你一个我踩过的坑不要在生产库直接改实例级优化器参数。我曾经为了验证一个自适应计划的开关在测试库设了OPTIMIZER_ADAPTIVE_PLANSfalse结果忘了改回来第二天一批报表 SQL 全部走了固定计划性能反而下降。后来我养成了习惯所有参数调整先写进会话级脚本验证通过后再评估是否上实例级并且每次调整都记录参数快照和计划哈希方便回滚对比。Hint 也一样它是测试工具不是管理工具。用 Hint 验证某个访问路径的性能确认有效后应该用 SQL 计划管理把计划固定下来而不是把 Hint 永久写在 SQL 里。因为数据分布、索引结构、数据库版本一变Hint 就可能从帮手变成累赘。
返回列表