前事不忘,后事之师,不忘国耻!

 用户注册  找回密码
 用户注册
搜索
查看: 23|回复: 0

[开发应用] Sybase ASE 统计信息治理实战:从计划退化到 update statistics 与 optdiag 巡检

[复制链接]

[开发应用] Sybase ASE 统计信息治理实战:从计划退化到 update statistics 与 optdiag 巡检

[复制链接]
dbaai

主题

0

回帖

404

积分

DBAAI

积分
404
12 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?用户注册

×
Sybase ASE 统计信息治理实战:从计划退化到 update statistics 与 optdiag 巡检


一、具体的问题

先说一个很多 ASE 老系统都会遇到的怪现象:某条查询过去几周都是毫秒级返回,业务没改代码、表也没怎么涨数据,某天突然变成十几秒;重启服务或者重建索引之后又恢复正常,过阵子又犯。还有一个更典型的:同一张表,查询条件里换个日期参数,计划就从索引 seek 掉到全表扫描,快慢差出两个数量级。

我自己在一个订单系统上就处理过:orders 表两千多万行,按 cust_id + order_date 查询,平时 200ms 以内,某个周一之后 P99 直接飙到 8 秒,应用层超时报错堆积。排查发现表数据其实只涨了 3%,罪魁祸首是统计信息——上一轮 update statistics 是七个月前跑的,这七个月里订单状态分布严重偏移(历史订单归档导致"已完成"占比从 20% 涨到 85%),优化器拿着陈旧的直方图估算行数,把一个明明可以走复合索引的查询估成了"返回 40% 的表",直接选了全表扫描。

这类问题的麻烦在于它不报错、不告警,只有业务方感受到慢。ASE 和有些数据库不一样,不会自动重建列的直方图,统计信息全靠 DBA 自己排程维护。很多从 MySQL、SQL Server 转过来管 ASE 的人,恰恰容易漏掉这一环。

二、核心原理

ASE 的基于成本的优化器做决策,依赖三类统计信息,全部存在系统目录里:

统计类型内容作用
列直方图(histogram)列值的分桶分布,每个桶记录上下界、频次、权重估算谓词选择性
密度(density)列(或列组合)的平均重复率估算等值匹配的返回行数
表/索引物理统计行数、页数、每页平均行数、页链信息估算 IO 成本


这些统计不是实时的。当你对表做大量 DML 之后,优化器手里的直方图和真实数据分布就脱节了——这就是"计划退化"的根源:查询没变,变的是优化器对数据分布的认知。

配套的治理命令有四个,职责要分清:


  • update statistics 表 (列):给指定列建/更新直方图,最常用,只动列统计,不重建索引;
  • update index statistics 表:更新索引全部键列(含复合索引的非前导列)的统计;
  • update all statistics 表:列 + 索引键全量更新,开销最大,只适合维护窗口;
  • delete statistics 表:删除列统计,用于清理无用的历史统计。


另外一个实用特性是采样:update statistics ... with sampling = N percent,大表不必全扫,采 10%~20% 通常足够优化器看清分布。更新统计信息后,ASE 会自动把引用该表的缓存计划作废、下次执行时重新编译,所以改完通常立刻见效,个别情况再配合 sp_recompile 补一刀。

三、实例参考(动手步骤)

步骤 0:确认现状基线

先别急着动手,把慢查询的执行计划和 IO 基线抓下来,否则治理完没法对比:
  1. -- isql 会话内
  2. 1> set showplan on
  3. 2> go
  4. 1> set statistics io on
  5. 2> go
  6. 1> set statistics time on
  7. 2> go
  8. 1> select count(*) from pubdb..orders
  9.    where cust_id = 12345 and order_date >= '2026-09-01'
  10. 2> go
复制代码

记录 showplan 输出里的表访问方式(TABLE SCAN 还是索引名)、logical reads 和耗时,这就是你的"治理前"证据。

步骤 1:用 optdiag 还原统计信息现场

optdiag 是 ASE 自带的统计信息导出工具,把 orders 表的统计完整倒出来看:
  1. optdiag statistics pubdb..orders -Usa -P'密码' -SSYB_ASE \
  2.   -o /tmp/orders_optdiag.txt
复制代码

打开输出重点看两处:


  • Last update of column statistics —— 列统计的上次更新时间。如果比业务高峰期早了好几个月,基本可以定性;
  • 直方图桶的分布 —— 对照实际数据分布,看关键列(如 order_status、cust_id)的桶是不是还反映现状。七个月前"已完成"订单只占 20%,直方图里最多的桶还停留在"处理中",这就是计划退化的直接证据。


步骤 2:更新统计信息

针对慢查询涉及的列精准补统计,先不动重型命令:
  1. -- 1) 慢查询谓词涉及的列,各建直方图,步数从默认 20 提到 100
  2. 1> update statistics pubdb..orders (cust_id) using steps 100
  3. 2> go
  4. 1> update statistics pubdb..orders (order_date) using steps 100
  5. 2> go
  6. -- 2) 复合索引的完整键列统计(含非前导列)
  7. 1> update index statistics pubdb..orders
  8. 2> go
  9. -- 3) 大表可用采样降低开销(15.x 支持)
  10. 1> update statistics pubdb..orders (order_status)
  11.    with sampling = 20 percent
  12. 2> go
复制代码

命令执行完 ASE 会自动作废相关缓存计划;如果存储过程行为还怪,补一句 sp_recompile pubdb..orders 强制引用它的过程下次重编译。

步骤 3:验证计划恢复

重跑步骤 0 的同一查询,对比三项指标:
  1. 治理前:TABLE SCAN,logical reads 1,842,000,duration 8.2s
  2. 治理后:IX_orders_cust_date,logical reads 12,400,duration 0.19s
复制代码

showplan 里访问方式从全表扫描回到索引扫描、logical reads 掉两个数量级,才算真的修复。没恢复就回去检查直方图步数是否够细、密度是否合理。

步骤 4:固化巡检,别再靠人肉

把 update statistics 排成每周维护作业,用 crontab 挂 isql 脚本:
  1. # /opt/dba/scripts/update_stats.sh
  2. #!/bin/sh
  3. isql -Usa -P"密码" -SSYB_ASE -i /opt/dba/sql/update_stats.sql \
  4.      -o /opt/dba/log/stats_$(date +%Y%m%d).log
复制代码

update_stats.sql 内容按"大表采样、小表全量、热点表高频"分级:
  1. -- 热点大表:采样 20%,每周
  2. update statistics pubdb..orders (cust_id, order_date, order_status)
  3. with sampling = 20 percent
  4. go
  5. -- 中小表:全量,每周
  6. update statistics pubdb..customers
  7. go
复制代码

crontab 里每周日凌晨 2 点跑,业务低峰,单表串行执行避免抢 IO。

治理前后对比

指标治理前治理后
慢查询 P998.2s0.19s
logical reads184 万页1.24 万页
应用超时报错40+ 次/天0
统计信息最长滞后7 个月≤7 天
计划退化复发每月 2~3 次0(3 个月内)
治理投入—每周 15 分钟维护作业


四、实操检查清单


  • [ ] 给每台 ASE 实例建档:核心大表清单 + 各表上次 update statistics 时间;
  • [ ] 用 optdiag 每月导出一次核心表统计,归档留底,方便事后追溯分布变化;
  • [ ] 慢查询排查顺序固定:先 set showplan/statistics io 抓计划 → 再 optdiag 看统计新旧 → 最后才考虑加索引;
  • [ ] 直方图步数按列基数分级:低基数列默认即可,高基数列提到 100~200;
  • [ ] 大表统一用 with sampling = 10~20 percent,避免维护窗口超时;
  • [ ] update statistics 之后必跑一次核心 SQL 回归,确认 showplan 符合预期;
  • [ ] 存储过程异常时用 sp_recompile 强制重编译,不要盲目重启服务;
  • [ ] 每周维护作业的日志落盘并巡检,作业失败要有告警;
  • [ ] delete statistics 只用于清理确认无用的列统计,删前先 optdiag 备份;
  • [ ] 变更大表数据(批量导入、归档、大量 delete)之后,主动补一次相关列的 update statistics,不等周作业。


几个容易踩的坑


  • 一慢就重建索引。reorg rebuild 顺带更新部分物理统计,看起来"治好了",但列直方图还是旧的,过几周必复发。先 update statistics,再考虑 reorg。
  • update all statistics 当日常手段。全量更新在千万级大表上能跑几十分钟还抢锁,放业务时间就是自己制造事故。日常用列级精准更新,全量只留维护窗口。
  • 只更新前导列。复合索引的非前导列也有独立查询场景,update statistics 表 只覆盖索引前导列,记得配 update index statistics 表。
  • 采样比例一刀切。分布极度倾斜的列(比如 95% 的行是同一个状态值)采样 10% 可能漏掉尾部分布,这类列要么全量、要么把采样提到 30% 以上。
  • 改完统计不验证。统计更新成功不代表计划一定变好,个别情况优化器仍选旧路径,必须用 showplan + statistics io 回归确认,形成闭环。


统计信息治理是 ASE 上性价比最高的优化手段:不花钱、不改代码、不动结构,一条命令换回两个数量级的性能。关键是把它从"救火动作"变成"每周例行",问题自然消失在发生之前。
免责申明1、欢迎访问本站,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@dbabbs.com
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

QQ|Archiver|小黑屋|DBA论坛中国 ( 鲁ICP备20017503号-2 )

GMT+8, 2026-10-30 17:55 , Processed in 0.019993 second(s), 9 queries , MemCached On.

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表