首页 > 数据库 >同样的SQL,怎么突然就慢了?

同样的SQL,怎么突然就慢了?

时间:2023-12-21 17:24:54浏览次数:26  
标签:DPR 索引 SQL AWR direct 问题 同样 突然

本篇文章素材来源于某银行系统的一次性能问题分析。

许久没写这种troubleshooting类型的技术文章了,因为曾在服务公司呆过多年,工作原因,这方面之前做的多,听的更多,导致已经达到在自己认知维度下的一个小瓶颈,纯技术型的问题,稍微常见的基本都遇到过,非常少见的也基本是bug类(软件缺陷只能通过补丁或一些workaround的方式绕过去),感觉实在是没啥可写的。

另外注意,我这里说的“常见”指的是所有客户群中相对常见,而对单个具体客户而言,就非常可能从没有见过,这也是纯甲方技术人员(这里的纯甲方是指毕业就在一个甲方呆着,只能看到自己公司系统运行情况)的局限性,在早些年时,一些行业前辈们还会建议新的技术从业者即使想去甲方,也要先在乙方吃几年苦,能多见一些场景,再去甲方,这样会有比较准确的判断力,不至于轻易被乙方忽悠,也不会瞎挑毛病挑不到点子上让人鄙视。

前些日子有客户遇到问题,申请出差过去现场帮客户分析解决了,这个分析过程还是有些意思的,但最终结论简单来说就是DPR(直接路径读)问题,定位那一刻就觉得没啥可写的了,相关文章也太多了,今天突然想换个思路,看能否以故事线的方式来呈现这个问题,并解释所有技术细节,试图能够让所有人(包括技术小白)都能看得懂,所有用户相关信息均已做遮蔽处理。

首先你要忘掉这是个DPR的问题,让我们一起体会下这个分析问题的历程。

起初是被同事叫来帮忙一起分析客户问题,搞了一个微信群,客户先发了一些所谓异常时间的AWR、ASH、ADDM报告。
说明环境是普通X86服务器上的一套Oracle RAC数据库,版本是11.2.0.4,有应用补丁,触发BUG风险相对较低。嗯,还是要强调下,这里说的低只是说主观感觉上,因为11g已经摸爬滚打了那么多年,无数客户曾趟出的bug也都做了修复,遇到新bug的概率相对小而已,但并不是遇不到,一旦运气不好遇到就麻烦了,所以我们现在会强烈建议你升级到现有的LTS(长期支持版本)19c,可不要再用11g了。

这里提到非常有用的报告:

  • AWR(Automatic Workload Repository)
  • ASH(Active Session History)
  • ADDM(Automatic Database Diagnostic Monitor)

其中ADDM相对用的少,它可以自动分析 AWR 中的性能数据,识别潜在的性能问题,并生成相应的建议报告。对于复杂问题可能不够准确,但至少也能给我们提供一个思路。
AWR可以记录某个时段下的真实负载情况,ASH可以在某个时段下看到是哪些会话在运行,非常好用,对等待事件的细致划分程度,也是其他数据库梦寐以求的东西。

和应用配合明确这个业务感知慢的SQL是否是AWR中显示的Top SQL,同时明确对应的具体sql_id,开始深入分析。
起初明确的sql_id,有一个对应的是一个存储过程,但此时没有进一步去查。
因为另外一个sql_id被认为更值得关注,这是一条简单的SQL,查询一个分区表,谓词条件只有一个定位到某一天的日期,该表是按月分区的。该SQL奇怪是正常的时候1分钟以内完成,异常的时候要接近10分钟完成,前者客户认为正常可接受,后者认为无法接受。

同样的SQL,查询不同日期,效率差距如此明显,另外客户反馈每天数据量基本相当,并没有数量级的差异。
此时最先想要排查的是是否有不同的执行计划?
可结果并不是,执行计划虽然是全表扫,但是前后并没有任何变化。
当时给的AWR中,我也看了IO部分,但只有3.3G的量级,感觉影响并不大,就忽略掉了。

后来去现场,实际动手分析发现,其实故障时刻远没有之前的AWR报告那样轻描淡写,重新收集后续故障时刻的AWR(1小时间隔)可以看到此时的DPR非常显著,达到了314G+,要是之前做紧急救援服务,看到这就已经结束了,直接凭借经验断定,DPR禁用掉再看效果。因为再慢的话,会影响其他客户问题的处理进度。

其实那种凭借历史经验直接判断问题虽然有很快很厉害的感觉,但却是不严谨的,现在我们要进一步确认细节,确认是否是这个问题。既然是DPR,再看TOP SQL中通过Reads的排序,发现Top 2都值得关注,因为物理读几千万,和后面SQL存在数量级上的差异:

Top 1是一个存储过程,Top 2是一个SQL,经确认这个SQL也是存储过程之内的一条SQL,但是并不是之前我们分析的那条SQL,说明之前提供的方向有一定错误。这也说明这个Top 2才是问题根本。

同时配合ASH也可以看到的确就是这SQL引发的DPR,导致性能严重下降。
到这里就可以相对稳妥的结案了。

可是呢,好巧不巧的在我介入分析之前,故障后应用侧试着调整了索引,变得可接受,但后来又变差,又重建索引,又重启了数据库,一系列操作,导致业务表现变好了,但是问题到底有没有解决,有没有隐患,都未可知。解释这一系列的问题,还需要继续深入分析更多的数据,找到证据证明这一切的因果。

首先,看看所谓变好的时刻,拿到AWR可以看到确实是没有千万级别的物理读了,而且问题SQL都不在TOP SQL中了。

而DPR呢,期间也下降到了18G的情况,比300多G那会儿是好太多了。也说明为什么最早3G多我会忽略,因为真的太小没太大影响,也不值当考虑。

下面来看这一系列的问题:

  • 1.调整了索引,变得可接受
    是因为有索引后,执行计划走了索引,没有引发这个SQL的DPR,所以效果变好。

  • 2.但后来又变差
    这里是因为执行计划又走错了,走回全表扫导致引发DPR。
    看下面这个查询结果,我们可以看到在变差的时段,全都是走了全表扫的372开头(PLAN HASH VALUE)的这个执行计划,而这个执行计划是DPR的方式,所以,虽然执行数千次,但是每次平均的DISK读都相当。

  • 3.又重建索引,又重启了数据库
    这个操作其实就是碰巧了,重启后走了好的执行计划,但以后不稳定的因素依然存在。

可是现在要如何来做呢?
其实在这个客户的系统情况下,讨论后还是建议要禁用DPR,因为DPR的设计初衷是,让那些偶尔访问的大表可以不对buffer cache产生大冲击,而默认这类大表操作次数是很小的,所以是好的设计。
但这个案例中,表不会特别大,也就是刚好超过“_small_table_threshold”的设置,但是却访问数千次,走DPR是一种灾难。

关闭Oracle 11g的DPR特性可参考:
https://www.cnblogs.com/jyzhao/p/6724299.html

简单来说,数据库不重启的话,就动态去设置这个隐藏参数:“_serial_direct_read”,相关操作参考:

--查询隐藏参数设置情况:
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND (x.ksppinm ='_small_table_threshold'  or x.ksppinm='_serial_direct_read');

--setting:设置隐藏参数为NEVER
alter system set "_serial_direct_read"=never;

--rollback:设置隐藏参数为默认值
alter system set "_serial_direct_read"=auto;
alter system reset "_serial_direct_read";

--永久生效:
SQL> show parameter event
SQL> alter system set event='10949 trace name context forever,level 1' sid='*' scope=spfile;

--其实也可以session级别更改,影响更小:
alter session set "_serial_direct_read"=never;

回顾下最初问题:同样的SQL,怎么突然就慢了?
执行计划没变时,是因为DPR这个特性导致,新分区虽然数据量和历史相当,但blocks却明显增多,超过了小表阈值。
后续建了索引变好,后又变坏,是因为有时候选错执行计划导致又走了全表扫又触发了DPR。

其实如果再想深究探索,还有好多可以思考的,比如,为什么新分区虽然数据量和历史相当,但blocks却明显增多?比如为何建立索引后有时又选错执行计划等等。只要你愿意,就又能探索到好多知识,即便Oracle已经非常成熟,但Oracle DBA也同样可以做的有技术深度。

最后要说的是,任何隐藏参数都是不建议用户主动去设置的,DPR这个虽然在很多服务商都建议最佳实践中都关闭,但是真正正确的打开方式是,要分情况,要在厂商指导下进行操作。比如举个极端的例子,如果用户使用Exadata一体机,上来就把DRP给关了,那就有些暴殄天物了,即便不是一体机,也看你的系统实际情况来决定,有些特性其实还是很好的,只是特定的一些场景下不适用而已,不过要真正分的清说的明这些内容,就还是要修炼自己的内功的。

标签:DPR,索引,SQL,AWR,direct,问题,同样,突然
From: https://www.cnblogs.com/jyzhao/p/17919502.html

相关文章

  • 在 MySQL 中,你可以使用 `AVG()` 函数来计算一组值或表达式的平均值。`AVG()` 函数的基
    在MySQL中,AVG()函数在计算平均值时会自动忽略NULL值¹⁴。也就是说,它只会计算所有非空值的平均值³。例如,假设你有一个包含以下值的列:90,80,70,85,95,NULL,NULL。在这种情况下,AVG()函数将只计算非空值的平均值,即:而不是将NULL值视为0并计算所有值的平均值。如果你需......
  • PostgreSQL从入门到精通教程 - 第39讲:数据库完全恢复
       PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUGPG技术大讲堂。 第39讲:数据库完全恢复 PostgreSQL第39讲:12月23日(......
  • centos7上源码安装postgresql 13.6
    1环境描述操作系统:Centos7.6postgresql:13.6安装方式:源码安装2创建用户#groupadd-g2000pgsql#useradd-u2000-gpgsqlpgsql3目录规划#mkdir-p/postgresql/{pgdata,archive,scripts,backup,pg13,soft,pg_log}#chown-Rpgsql:pgsql/postgresql#......
  • postgresql常用创建用户和授权
    需求(1)给用户a创建一个数据库,并且给a用户对这个库有所有权限(2)给read_a用户对这个数据库有只读权限步骤1.创建用户a2.创建数据库db_a,并设置owner为a3.回收默认的publicschemacreate权限4.设置db_a的publicschema默认的owner为a5.创建只读用户read_a6.用a用户给read_a......
  • mysql
    MYSQL1.安装2.用法sql语句可单行或多行,以分号结尾;MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。单行注释:--注释内容或#注释内容(MySQL特有)多行注释:/*注释*/3.mysql数据类型​ 数值:tinyint:1个字节(小整数类型)int:4个字节(大整数类型)double......
  • docker初步入门学习安装redis和mysql
    dockerrun--namemyredis-p6379:6379-dredisredis-server--appendonlyyesdockerrun--namemysql-eMYSQL_ROOT_PASSWORD=123456-d-p3306:3306mysql:5.7.27dockerpullmysql:5.7.27dockerrun-d--hostnamemy-rabbit--namemyra......
  • 突然想到了一个办法针对枚举可以解决一些常量的冗余写法
      {"commodityCode":"Code测试","userId":"1","count":1000,"money":9}!财经网讯实际情况!财经网讯excel里面给的??财经网评论实际情况?财经网评论excel里面给的到财财内容like'%?财经网讯%'内容like'%?......
  • sql server pre-login troubleshooting
    wireshark抓包之后,首先过滤数据库服务器的IPip.src==172.22.58.4orip.dst==172.22.58.4找到第一条TCP握手记录之后,右键选中,FollowTCPstream然后会自动标记筛选出,从握手到断开的所有packet数据包tcp.streameq56 UsingSQLServer’sSNITracetoTroubleshootNetwor......
  • MySQL 8 半同步复制
    安装半同步复制半同步复制是通过插件的形式实现的。必须要在源库和副本上安装插件。源库和副本有不同的插件。插件安装后,可通过与之相关的系统变量对其进行控制。只有安装了相关插件,这些系统变量才可用。要使用半同步复制,必须满足以下要求:·要求MySQL服务器支持动态加载。要......
  • SQL SERVER上课笔记
    SQL数据库笔记##############目录 SQL数据库笔记############## 一、初次使用数据库 .二、用SSMS工具工具采用图形化的方法创建数据库(第二种方法通过T-SQL语句创建数据库) 三、利用T-sql创建数据库 四、删除数据库 五、数据库的相关操作分离,附加,改变数据库......