我最早注意到 YashanDB 的数据利用率问题,是在一次数据库巡检的时候。客户的业务库跑了大半年,磁盘空间用掉了将近 70%,但我和团队把表清单拉出来一看,真正被最近三个月业务访问过的核心表,占比不到一半。大量历史数据堆在那里,索引又多又杂,统计信息长期没更新,备份集更是只进不出——这几乎是很多 YashanDB 用户都在面临的状况:数据库本身不慢,但你并没有把它的能力真正用起来。
这个“数据利用率”听起来有点虚,实际上可以拆成几个很实在的维度:存储空间有没有被有效数据占据,还是被过期数据、冗余索引和碎片白白吃掉;查询有没有走对执行计划,让数据真正被业务高频消费;数据质量是否可信,能不能放心地交给分析平台和下游系统;以及备份、归档这些“冷”数据,是不是除了出事之外就永远躺在那里。这篇文章我就从这四个层面出发,结合我自己在 YashanDB 上的实操经验,把提升数据利用率的完整思路和具体命令整理出来。无论你是在做运维、负责数据治理,还是刚接触国产数据库的开发者,应该都能从中找到可以直接拿去用的方法。
1. 先把问题讲透:数据利用率低下的根源
1.1 “利用率”不是一个玄学指标
很多同学一听到“数据利用率”,第一反应是“这玩意儿怎么量化”。实际上它可以从多个角度来度量,咱们逐个拆开看。
第一层是空间利用率。这个最直观,就是实际存放的有效业务数据占已分配存储空间的比例。如果一个 2TB 的表空间里,有一半是被三年前的历史流水、临时中间表、回收站对象和索引碎片占用的,那空间利用率就是不及格的。第二层是活跃数据占比。一个表中最近半年被查询、更新、统计的数据条数占总行数的比例。如果不做冷热分层,热数据和冷数据混在一个大表里,查询扫描的成本会被无限放大。第三层是查询有效率,也就是 SQL 执行时是否走了正确的执行计划,有没有因为统计信息缺失、索引失效或者 SQL 写得不好而做了全表扫描。第四层是数据可信度。如果表里的数据有大量空值、重复值、格式不一致,下游分析和业务系统就不敢用、不愿用,那这些数据即使躺在库里也是“死数据”。
你把这几层叠在一起看,就会发现“提升数据利用率”这个目标,其实是个系统工程。它不只是调一条 SQL、加一个索引那么简单,而是从存储规划、查询优化、数据治理到数据服务的一整套动作。我后面讲的所有技巧,都是围绕这几个层次展开的。
1.2 低利用率的典型业务场景
我在实际项目中见过太多“数据利用率低下”的典型案例,这里说几个最有代表性的,你看看自己库里面是不是也有类似现象。
场景一:客户交易系统上线三年,流水表已经积累了上亿行。这张表既有当前的订单状态,又有三年前的归档数据。每次跑月度报表,查询条件里只有时间范围,结果优化器因为统计信息不准确,选了一个糟糕的执行计划,一条报表 SQL 跑十几分钟。大家的第一反应是加硬件,但根本问题是数据堆在一起,冷热不分。场景二: DBA 为了“保险”,给一张表的每个字段都建了索引,结果一张表挂了三十几个索引,数据写入时索引维护成本极高,查询时优化器反而因为索引选择过多而发出错误的执行计划。真正高频使用的索引只有四五个,剩下的都是冗余。场景三:备份策略只做了“备份”,没有做“恢复演练”,备份集在磁带和对象存储里躺了两年,从没验证过可恢复性。一旦真出事,发现备份文件有缺失,那时候哭都来不及。同时,这些备份数据从来没有被用于搭建测试环境或做数据分析,白白浪费了宝贵的“真实数据资源”。
这四个场景,分别对应了存储、索引、统计信息和备份利用四个方面的问题。我下面的内容就是针对这些问题给出可落地的解法。
2. 存储层面的利用率提升:让每一GB都花在刀刃上
2.1 冷热分层:分区与归档的组合拳
YashanDB 中做冷热分层最核心的手段就是分区表加归档策略。用生活化的方式理解,分区表就像把一个大仓库按货架分区,1 月的数据放 1 号货架,2 月的数据放 2 号货架。查询时如果要取 2 月的数据,只需要去 2 号货架拿,不用翻遍整个仓库。这带来两个直接收益:查询效率提升,因为分区裁剪让扫描量大幅减少;数据生命周期管理变得容易,因为可以按分区单独清理、归档、压缩。
建分区表的思路很简单,核心是按时间范围分区。我在 YashanDB 兼容 Oracle 语法的模式下,常用的建表语句长这样:
CREATE TABLE orders ( order_id NUMBER(12), customer_id NUMBER(12), order_date DATE, order_amount NUMBER(10,2), status VARCHAR2(20) ) PARTITION BY RANGE (order_date) ( PARTITION p2023_q1 VALUES LESS THAN (TO_DATE('2023-04-01','YYYY-MM-DD')), PARTITION p2023_q2 VALUES LESS THAN (TO_DATE('2023-07-01','YYYY-MM-DD')), PARTITION p2023_q3 VALUES LESS THAN (TO_DATE('2023-10-01','YYYY-MM-DD')), PARTITION p2023_q4 VALUES LESS THAN (TO_DATE('2024-01-01','YYYY-MM-DD')) );注意几个要点。第一,分区列的选取很关键,一定要选业务上最常见的查询过滤条件。如果报表和业务查询都是按时间范围来的,按时间分区就是最优解;如果经常按区域查询,可以考虑 LIST 分区,但实际运维中时间分区用得最多。第二,不要把分区粒度搞得太细,比如按天分区,一年就是 365 个分区,分区过多会导致元数据管理成本上升。我一般建议按季度或按月分区,除非有特殊的数据生命周期要求。第三,当分区数量多到一定程度,建议使用间隔分区(INTERVAL),让数据库自动创建新分区,避免每个月手工加分区的繁琐操作:
CREATE TABLE orders ( order_id NUMBER(12), customer_id NUMBER(12), order_date DATE, order_amount NUMBER(10,2), status VARCHAR2(20) ) PARTITION BY RANGE (order_date) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH')) ( PARTITION p_first VALUES LESS THAN (TO_DATE('2023-01-01','YYYY-MM-DD')) );归档策略上,我常用的做法是分三步走。第一步,超过一年(或业务规定周期)的历史分区,做压缩处理,减少存储占用。第二步,超过三年(或更久)的分区,从主表分离出来,放入归档表空间,必要时甚至可以搬迁到更廉价的存储介质上。第三步,超过五年的数据,评估是否还需要在线保留,不需要的直接 truncate 分区并备份到离线归档,需要保留但访问极少的,导出到归档库或数据湖。
2.2 压缩与行/列混合存储
压缩是提升空间利用率最直接的手段。YashanDB 提供了丰富的压缩选项,关键在于按数据特征选择合适的方式。我在给客户做优化时,经常看到有人不分青红皂白地对所有表开启压缩,这其实是个误区。压缩是要消耗 CPU 的,对于写入频繁的 OLTP 表,过度压榨反而会拖慢事务响应。
实务中的压缩策略应该是“按热度差异化”。核心交易表、频繁更新表不压缩或轻度压缩;历史流水、日志、归档类表用高级压缩或混合列压缩,这类表写入后基本不更新,读多写少,压缩收益最大。YashanDB 中可以在建表时指定压缩属性,也可以对已有表在线修改:
-- 创建归档表时直接指定压缩 CREATE TABLE orders_archive ( order_id NUMBER(12), customer_id NUMBER(12), order_date DATE, order_amount NUMBER(10,2), status VARCHAR2(20) ) COMPRESS FOR QUERY HIGH; -- 修改已有表的压缩属性 ALTER TABLE orders_archive COMPRESS FOR QUERY HIGH;列存储的适用场景也要说清楚。如果一个表经常做聚合分析,比如 SUM、AVG、GROUP BY 这种只需要读取少数列的查询,列存可以让扫描的数据量大幅下降。但列存不适合高频单行插入和更新。所以我的建议是:分析类报表、数据仓库层的大宽表,可以考虑列存模式;在线交易类的表用行存;如果一张表既承载查询又承载分析,可以用分区级别的方式把不同分区设置为行存或列存,做到真正的“混合存储”。这些能力 YashanDB 都支持,具体用哪种要看你的业务模式,不能拍脑袋。
2.3 表空间与文件布局规划
存储利用率不只是“压缩”两个字,表空间的合理规划同样重要。很多新手 DBA 的习惯是建一个巨大的 USERS 表空间,把所有表、索引全部塞进去。这样做表面上简单,实际上会导致空间管理混乱,无法做细粒度的资源控制和维护。
我更推荐按数据生命周期来划分表空间。数据量小的时候区分度不用太细,但至少要把“当前活跃数据”“历史归档数据”“索引数据”分开放置。这样设计的直接好处是:做备份时可以只备份活跃表空间,归档表空间备份频率可以降低,节省备份时间和存储成本;做表空间迁移时可以把归档数据放在机械盘或低成本存储上,活数据放在高性能盘上;排查空间问题时,能快速定位是哪个部分在膨胀。
另外要定期监控表空间的碎片率。如果一个表空间内的对象经过大量 delete、update 操作后,区间碎片化严重,会导致空间利用率下降。虽然 YashanDB 会自动管理段空间,但在删除大量历史数据后,建议对对应的表或分区做一次收缩操作,把空洞释放出来:
ALTER TABLE orders SHRINK SPACE CASCADE;这里有个操作细节值得提醒:SHRINK 操作需要表开启行迁移(ROW MOVEMENT),如果表上有依赖视图或物化视图,操作前一定要确认影响范围。我踩过这样的坑:在业务高峰期直接对一张大表做 SHRINK,结果因为行迁移触发了大量行锁,导致应用侧出现短暂的写阻塞。正确的打开方式是,先评估表大小和碎片率,把收缩操作安排在维护窗口,并且分批次执行。
3. 查询层面的利用率提升:把数据真正“用起来”
3.1 统计信息是查询优化的地基
很多查询性能问题,根源不在 SQL 写得差,而在统计信息不准确。YashanDB 的优化器跟大多数主流数据库一样,是基于成本优化的,它要判断走索引还是全表扫描、选择哪种连接方式,依赖的就是表和索引的统计信息。如果统计信息长期不更新,优化器拿着一张“过期地图”做决策,出现糟糕执行计划是必然的。
我见过一个典型场景:一张订单表从 100 万行涨到 1000 万行,统计信息还是 100 万行时收集的。优化器以为走索引只需要扫几千行,实际扫了几十万行,结果一条本来应该毫秒级返回的查询跑了好几秒。这种问题排查起来很隐蔽,因为 SQL 本身没问题,索引也存在,但就是慢。所以,统计信息的收集必须纳入日常运维规范。
YashanDB 兼容主流数据库的统计信息管理方式,推荐的收集策略是:每日或每周对变更量大的核心表收集一次统计信息;批量任务或 ETL 加载完成后,立即对目标表收集统计信息;每月对整个 Schema 做一次全量统计信息收集。常用的收集命令风格如下:
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'ORDERS', CASCADE => TRUE); EXEC DBMS_STATS.GATHER_SCHEMA_STATS(USER, OPTIONS => 'GATHER AUTO');收集统计信息的时间选择也很讲究。我一般排在业务低峰期,并且先用预估耗时的方式采样。对大表来说,全量统计信息收集可能耗时很长,可以先用 AUTO_SAMPLE_SIZE 让数据库自动决定采样比例,不要手动指定一个过小的采样率,否则收集出来的直方图不准确,优化器照样走错路。
3.2 索引“少而精”设计思路
索引是把双刃剑。查询的时候它帮你加速,写入的时候它拖你后腿。很多系统越跑越慢,一个重要原因就是索引膨胀——每次业务改版加一个新索引,但老索引从不清理,久而久之索引占用的空间和数据量几乎持平,甚至超过数据本身。
我在 YashanDB 上做索引治理时,遵循三个原则。第一,索引必须服务于具体的高频 SQL 模式。如果一个索引建好之后,从来没有出现在执行计划里,那它大概率是冗余的。第二,联合索引的列顺序要优先匹配等值查询条件,然后才是范围查询和排序条件。第三,区分度低的列(比如性别、状态)不适合单独建索引,建了也是白建,优化器基本不会用。
检查冗余索引是可以在数据库里直接做的。通过查询动态性能视图,找出有哪些索引从未被使用过:
SELECT index_name, table_name FROM user_indexes WHERE index_name NOT IN ( SELECT DISTINCT object_name FROM v$object_usage -- 视各版本实际可用视图为准 ) ORDER BY table_name;清理冗余索引时,不要直接 DROP,我建议先标记为不可用(UNUSABLE)或者先停用一段时间,观察业务是否出现查询变慢的反馈。确认无影响后再物理删除。这样做的原因很实际,有些时候索引没被记录到使用统计里,是因为查询走了别的路径,但某些低频的复杂查询其实还依赖它。直接删掉风险太大,先软后硬的方式更稳妥。
3.3 SQL 改写与执行计划调优
数据利用率提升到执行计划这一层,就已经进入“硬功夫”阶段了。同样的业务需求,SQL 写法不同,执行计划可能天差地别。我总结了几种常见的“看起来没毛病,实际上很伤”的写法。
第一种是索引列上做函数运算。比如在 order_date 列上写 WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2024-01-01',这会让索引失效,因为优化器无法对函数处理后的结果做索引匹配。正确写法是 WHERE order_date >= TO_DATE('2024-01-01','YYYY-MM-DD') AND order_date < TO_DATE('2024-01-02','YYYY-MM-DD')。第二种是隐式类型转换。如果列是 VARCHAR2 类型,查询条件里却写成了数字,数据库会隐式把列做转换,同样可能导致索引失效。第三种是深分页问题。报表系统常见的 OFFSET 1000000 ROWS FETCH NEXT 20 ROWS ONLY 这种写法,数据库要把前一百万行全部扫描并丢弃,之后才返回 20 行。效率极低,尤其是数据量大的时候。这种情况下,更聪明的做法是记录上一页的最后排序值,用“键集分页”的方式去取下一页,比如 WHERE order_id > 1000000 ORDER BY order_id FETCH NEXT 20 ROWS ONLY。这样每次查询都只走索引的一小段,速度和稳定性都会好很多。
在 YashanDB 中分析 SQL 问题,第一步是拿到执行计划。可以用执行计划开关,或者通过管理工具查看,核心关注点有三个:是否发生了全表扫描;有没有额外的排序操作;表连接顺序是否合理。我拿到一条慢 SQL,从来不会急着改 SQL,而是先看执行计划,因为只有看清优化器“实际怎么走”,才能定位问题到底出在统计信息、索引缺失还是 SQL 语法本身。
4. 治理层面的利用率提升:让数据可信、可用
4.1 冗余与过期数据清理实战
让数据库里只留“应该留的数据”,这句话说起来轻巧,做起来要动刀。YashanDB 库里常见的数据冗余和过期包括:临时表、中间表长期滞留;业务软删除标记了但没清理的历史数据;重复执行 ETL 产生的重复数据;以及回收站里的对象。每一类都有对应的处理方式。
先查一下有没有长期不用的临时表和中转表:
SELECT table_name, num_rows, last_analyzed FROM user_tables WHERE table_name LIKE 'TMP_%' OR table_name LIKE 'TEMP_%' ORDER BY last_analyzed;这类表如果超过一个月没更新,基本可以确认是“僵尸表”,确认没有下游任务依赖后直接删除即可。对于业务表的过期数据,我推荐的方法是“分批删除”,不要一次性 DELETE 几百万行。一次性大事务删除会带来三个问题:产生大量 undo 日志,可能导致回滚段膨胀;长时间持有行锁和表锁,影响在线业务;一旦中途失败,回滚成本极高。分批删除的写法大概是这样:
DECLARE v_cnt NUMBER; BEGIN LOOP DELETE FROM orders WHERE order_date < ADD_MONTHS(SYSDATE, -24) AND ROWNUM <= 10000; v_cnt := SQL%ROWCOUNT; COMMIT; EXIT WHEN v_cnt < 10000; END LOOP; END;分批删除的时间窗口要选在业务低峰期,每批删除的规模根据表的负载情况动态调整,1 万行只是一个起始参考值,如果系统负载高,可以降到 2000 行一批。删除完成后,记得对表重新收集统计信息,释放空间。
4.2 数据质量规则与常态化校验
数据可信度的提升,是决定数据利用率上限的关键一环。如果数据质量没保证,哪怕存储和查询都调优得再好,业务方还是会觉得“这库里的数据不敢用”,最后绕开数据库做一套自己的 Excel 报表——这种情况在很多公司都真实存在。
数据质量校验我一般从三个维度入手。完整性,核心字段有没有空值、默认值是否正确;唯一性,业务主键是否存在重复;一致性,同一份数据在不同表中是否对得上。YashanDB 里面用 SQL 就能做基础巡检。比如查订单表的空值率:
SELECT COUNT(*) AS total_cnt, COUNT(order_amount) AS amount_not_null_cnt, SUM(CASE WHEN order_amount IS NULL THEN 1 ELSE 0 END) AS amount_null_cnt FROM orders;查出异常之后,要形成一份“数据质量基线”。比如核心客户表的客户号字段空值率不得高于万分之五,订单金额的负值比例不得高于万分之一。基线定好之后,通过定时任务每天检查,一旦指标超出阈值就告警。这套逻辑不需要额外买工具,一个存储过程加一张规则配置表就能实现,但它带来的数据可信度提升,价值远远超过开发成本。
4.3 让沉睡的备份数据“再次上岗”
备份数据是利用率提升里最容易被忽略的一块。很多企业做备份是为了“万一出事能恢复”,但备份集每天产生,存储成本却在不断增加。如果能把这些“沉睡”的数据利用起来,备份就不再是纯成本,而是一份可以反复使用的数据资产。
最常见的利用方式,是用备份集搭建测试环境。开发联调和测试环境最缺的就是“像生产一样的真实数据”,但直接在生产库导数据又存在安全风险和时间成本。用备份恢复的方式创建一个测试库,数据是最新的、完整的,操作也相对规范。YashanDB 的备份恢复工具支持将备份集恢复到指定时间点,恢复之后直接把测试库地址发给开发团队,大大缩短了准备测试数据的周期。这里要强调的是,用生产备份搭测试环境时,必须做好敏感数据脱敏,否则一旦测试库泄露,就是严重的合规事故。
另一个思路,是定期用备份数据做“生产数据对账”。有时候生产环境的数据被误操作改掉了,但因为时间过了很久,无法确定是哪一笔变更导致的。这时候可以用一周前的备份集恢复出一个临时的对账库,比对两张表的数据差异,精确找到被修改的记录。这种操作我在实际救火中用过多回,每次都比翻日志高效得多。
备份数据的价值还不止这些。历史备份集也是做数据分析和挖掘的金矿。比如分析某个月的订单趋势,但线上库为了控制空间已经把那个月的分区删了,这时候只要找到那个时间点的备份集,恢复出来就能补回数据缺口。所以备份策略的设计,不应该只考虑“能不能恢复”,还要考虑“备份数据能支撑哪些分析需求”,这会让数据库管理员的工作从被动运维变成主动赋能。
5. 服务层面的利用率提升:降低数据消费门槛
5.1 视图与数据服务化
数据利用率的最后一道坎,是“数据好不好取”。就算库里的数据再全、质量再高,如果业务方不知道表结构、不清楚字段含义、不敢写复杂 SQL,数据还是用不起来。视图是我在所有 YashanDB 项目中都会建议大量使用的一种对象。
视图的价值在于“封装复杂性、暴露业务语义”。比如业务方需要一份“本月有效订单汇总”,他不需要知道底层是七张表 join,也不需要理解各种状态字段的值含义,只需要 SELECT * FROM v_monthly_valid_orders 就能拿到结果。这大大降低了数据消费的门槛。建视图的时候有一个原则要记住:视图只做逻辑封装,不要在视图里做太多层嵌套,否则一旦底层数据量变大,视图查询的性能会很难控制。简单的过滤、字段改名、基础关联放在视图里是合理的,复杂的聚合和指标计算尽量放在物化视图或数据加工层。
5.2 数据同步与汇聚
数据利用率提升的另一个方向,是让更多系统能“接上”YashanDB 的数据。现在的企业数据环境基本都是多源异构的,YashanDB 里存的是业务核心数据,分析平台在另一个数仓,数据湖里又有一份导入的历史数据。如何让数据高效地在这些系统之间流动,直接决定了数据被消费的范围和频率。
YashanDB 提供了数据同步和对外接口的能力,可以配合常见的 ETL 工具做周期性的数据抽取。这里我的实操建议是:同步任务的设计一定要有“断点续传”和“增量抽取”机制。很多团队一开始图省事,每天全量抽取整张表,数据量小的时候看不出问题,等表涨到几千万行,全量抽取的时间会越来越长,最终变成运维事故。增量抽取的正确打开方式是:源表上必须有可靠的增量字段,最常用的是自增 ID 或最后修改时间,并且这个字段上要有索引。如果源表本身没有这些字段,就要在上游业务写入时同步维护,这是数据架构层面需要提前规划的。
数据汇聚方向也有讲究。不要把 YashanDB 直接暴露给所有下游系统随意查询,而是在中间加一层数据服务或数仓层。这样做的好处是:可以隔离下游系统的查询压力,不会因为某个分析团队的复杂查询把核心交易库拖垮;可以在中间层做统一的数据质量校验和口径管理,保证每个系统拿到的数据是一致的。我在实践中看到过太多“每个团队直连生产库,各自跑各自的报表”的例子,最后大家拿到的数字互相矛盾,吵得不可开交。
5.3 元数据管理与数据地图
元数据管理是提升数据利用率一个“功在当代、利在千秋”的环节。很多数据库里几十张核心表,字段命名用的是 order_id、c_xxx、f_xxx 这种只有开发才懂的缩略语,业务分析师打开表结构就像在看天书。没有清晰的元数据标注,数据利用的门槛就永远降不下来。
我建议在 YashanDB 的数据字典中维护字段级别的业务注释。如果表已经建好,可以通过 COMMENT 语句补充:
COMMENT ON TABLE orders IS '订单主表'; COMMENT ON COLUMN orders.order_id IS '订单唯一编号,主键'; COMMENT ON COLUMN orders.customer_id IS '客户ID,关联 customer 表'; COMMENT ON COLUMN orders.order_date IS '下单时间,精确到秒'; COMMENT ON COLUMN orders.order_amount IS '订单金额,单位元,保留两位小数';同时,在外部建一张元数据管理表,记录表名、字段名、业务口径、数据负责人、更新频率和下游消费方。有了这张“数据地图”,新来的数据分析师可以自助查数,不需要每次问开发这个字段是什么意思;数据治理团队也能快速盘点出哪些表是核心资产、哪些表可以下线。这个动作不需要一次性做完,可以按核心表优先级逐步覆盖,但每覆盖一张表,那批数据被使用起来的概率就会高一大截。
6. 常见问题与排查技巧实录
在提升 YashanDB 数据利用率的过程中,有几个问题几乎是每个项目都会踩到的,我整理成了一张速查表,方便你直接对号入座。
| 问题现象 | 根本原因 | 排查手段 | 解决方案 |
|---|---|---|---|
| 磁盘空间持续增长,但有效数据没多少 | 过期数据堆积、回收站未清理、表空间碎片化 | 查看各表空间使用率、用户表中过期数据量、回收站对象 | 分批清理过期数据、定期 Purge 回收站、对碎片化严重的表做 Shrink |
| 同一张表查询时快时慢 | 统计信息陈旧,优化器选择不稳定 | 查看表的 last_analyzed 时间和行数变化 | 按变更频率定期收集统计信息,在批量任务后强制收集 |
| 索引建了很多,查询依然慢 | 索引设计不合理,或索引未被使用 | 动态性能视图查看索引使用情况 | 删除冗余索引,按高频 SQL 重建联合索引 |
| 备份文件占用大量低成本存储,但从未被使用 | 备份策略只考虑恢复,不考虑数据再利用 | 梳理备份集保留周期和恢复成功率 | 定期恢复演练,用备份搭建测试库,对备份集做分析利用 |
| 业务方反映“数据不敢用” | 字段含义不清、数据质量无保障 | 抽查核心表完整性、唯一性、一致性 | 补充字段注释,建立数据质量基线校验 |
| 报表查询消耗过大,影响生产业务 | 下游直连生产库跑分析查询 | 查看活跃会话的 SQL 来源 | 中间加数据服务层或数仓,下游走读写分离节点 |
除了这六个高频问题,我再分享一个排障时容易忽略的细节。在 YashanDB 中排查性能问题时,不要只盯着慢 SQL,还要看它的并发度。一条 SQL 单独执行不慢,但被几十个会话同时执行,就会把 I/O 和 CPU 打满。这种情况下的调优思路不是改 SQL,而是做查询缓存、结果集复用或者错峰调度,把集中式的查询压力打散到不同的时间窗口中去。
还有一个经验是从一次大促保障中总结出来的。当时我们发现历史分区数据还在参与查询,导致大促当天的核心查询偶尔会变慢。排查后发现,报表系统有一条“近两年所有订单”的汇总查询,每次都会扫描所有历史分区,把大量冷数据拉到内存过滤。我们的处理方式是给报表建立独立的汇总表,在业务低峰期用物化方式刷新,大促当天直接查汇总表,彻底绕开历史分区。这个改动不仅让报表查询从秒级提升到了毫秒级,还释放了大量内存和 I/O 资源。这背后其实就是“让正确的数据在正确的位置被使用”的思维——提升利用率,不只是在优化工具,更是在优化整个数据使用的路径。
最后再补充一个我在 YashanDB 上反复验证过的小技巧:在对大表做结构调整(比如加字段、改压缩属性、启停分区)之前,先通过查询数据字典确认这个表上是否有正在运行的长事务或锁等待。很多 DDL 操作在 YashanDB 中虽然可以实现在线执行,但遇到高并发写入时仍然会产生锁竞争。选一个明确的维护窗口,提前通知业务方,把调整脚本、验证脚本、回退脚本都准备好再动手,这样的操作流程,才是保证数据利用率提升工作能够持续落地的前提。