数据库管理第174期 执行计划的改变竟如此复杂(20240423)

2024年 4月 23日 44.1k 0

数据库管理174期 2024-04-23

  • 数据库管理-第174期 执行计划的改变竟如此复杂(20240423)
    • 1 大量等待
    • 2 性能问题排查
    • 3 为什么执行计划会改变
      • 3.1 统计信息不准确
      • 3.2 表数据量过大
      • 3.3 错误索引
    • 4 优化建议
    • 总结

数据库管理-第174期 执行计划的改变竟如此复杂(20240423)

作者:胖头鱼的鱼缸(尹海文)
Oracle ACE Associate: Database(Oracle与MySQL)
PostgreSQL ACE Partner
国内某科技公司 DBA总监
10年数据库行业经验,现主要从事数据库服务工作
拥有OCM 11g/12c/19c、MySQL 8.0 OCP、Exadata、CDP等认证
墨天轮MVP、认证技术专家、年度墨力之星,ITPUB认证专家、专家百人团成员,OCM讲师,PolarDB开源社区技术顾问,OceanBase观察团成员
圈内拥有“总监”、“保安”、“国产数据库最大敌人”等称号,非著名社恐(社交恐怖分子)
公众号:胖头鱼的鱼缸;CSDN:胖头鱼的鱼缸(尹海文);墨天轮:胖头鱼的鱼缸;ITPUB:yhw1809。
除授权转载并标明出处外,均为“非法”抄袭

本期源自于上周一晚上11点过处理的一个性能问题,一体机上的一个PDB突然出现了大量的等待,且看问题是如何处理并如何分析的。

1 大量等待

在我维护Oracle的历史中,latch: cache buffer chains是出现过很多次的,有因为BUG出现的、也有因为一些操作触发的、还有因为数据库配置异常导致的。
本次的异常语句大致如下:

select count(*) from tabX where A=:1 and B=:2;
select * from (select A,B,C,D,E... from tabX where A=:1 and B=:2) where rownum'USERX',tabname=>'TABX',cascade=>true,degree=>16);

然后启动service:

srvctl start service -db dbaas -s Xservice

这时应用侧再处理其他问题,同时检查语句执行情况,恢复正常。

2 性能问题排查

首先,按照习惯重新收集了统计信息,那么首先排查执行计划,这里可以通过下面的语句来收集对应时段的SQL执行计划(How to Determine the Execution Plan for a SQL Statement for a Range of AWR snapshots? ( Doc ID 795204.1 )):

@?/rdbms/admin/awrsqrpt.sql
-- 这里需要在对应实例执行
-- 和生成AWR报表一样需要输入时段对应的快照编号
-- 需要输入对应的SQL_ID

由于涉及生产系统,这里不便展示,但是结论就是,正常时段,两条语句执行计划走的是A列的索引IDX_A,而异常时段走的确实B列上的索引IDX_B。
这是SR也反馈,这两条语句在半小时的IO(主要是buffer get)也超过了6TB,而平时的IO则很小,回去看看表的数据量:

select count(*) from tabX;

COUNT(*)
----------
117281393

这个表的实际数据量超过了1.17亿,同时该表为分区,你没有看错,没有分区!
同时与业务方一起对表数据进行检视,发现A列数据基本上都是唯一的,而B列数据存在大量重复内容。这两条语句也是大部分业务操作的前置操作,因此并发量不小。
那么执行计划异常走到了IDX_B是导致本次问题的主要原因,由于IDX_B选择性较低,走这个索引效率就会比较低,大概率还会回表扫描引起较大的IO。

3 为什么执行计划会改变

其实这次故障客户最大的疑问就是日常运行正常,突然除了问题,处突完成后又正常了,其实执行计划变更下面几个原因:

3.1 统计信息不准确

在这次处突过程中,做了重新收集统计信息的操作,统计信息和执行计划生成又是强相关的,那么如果统计信息不准确肯定可能造成执行计划不准确。19c开始统计信息收集是不需要添加过多参数,会自动判断是否需要收集额外的统计信息,比如多列、直方图、索引等等,并自动选择采样比例;自动统计信息收集也会选择收集频率。但是如果表数据十分复杂,且如果采样的内容不合理也可能出现一些问题。
但是本次很奇怪,11点过出现问题,不在自动统计信息的维护窗口内,应该不是新收集的统计信息引起的问题,那么我们姑且先把统计信息不准确放在这。

3.2 表数据量过大

单表数据量过大,且没有分区会造成需要在磁盘和内存之间交互的数据量增大,影响IO。这次对应的表数据量大且没有分区,语句走了错误的索引造成大量IO。这可以算是错误执行计划引起了错误的结果了。当然数据量过大也增大了统计信息准确收集的难度。

3.3 错误索引

众所周知,索引的适用场景是从大量数据中获取少量数据,并不适合获取较多的数据,也就不适合用在重复值较多的列上。在本次问题中,涉及的两个列都建了独立的索引,相当于给优化器说,我给了你两条路选择,当统计信息不准确、表数据量较大和其他一些问题的时候,给了优化器一个“幻觉”,让它走了第二条路,生成了错误的执行计划。而且不合理的索引也增加了统计信息收集准确的难度。

4 优化建议

  1. 干掉不合理的索引,让优化器没有走错路的可能性(提升统计信息准确程度)(如果无法干掉,则使用hint指定索引或SPM固定执行计划)/或者以合适列为引导列建立合适的复合索引
  2. 控制表的数量,尽量分区,减少出现大IO的可能性(提升统计信息准确程度)
  3. 如果表内数据变化较大,可以在自动维护窗口外,业务压力较小的时候增加手动统计信息收集
  4. 针对本次问题的具体语句,在没有必要的情况下使用子查询,有可能对临时表空间容量带来压力(本次未发生),为了避免该问题发生,根本解决方案是干掉子查询,由于应用无法改动,只能先增加临时表空间

总结

数据库的问题其实大多数还是源自于应用程序设计和数据库逻辑设计层面。
老规矩,知道写了些啥。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论