一条SQL直接跑崩288核,1.5T内存数据库

最近遇到一个Oracle的SQL语句引发的线上故障,数据库服务被重启。主机288核,1.5T也没抗住。

复制代码
select  count(*) from dev_db.t1 t1,dev_db.t2 t2 where t1.object_name = t2.object_name or t1.DATA_OBJECT_ID = t2.DATA_OBJECT_ID and t1.OBJECT_ID = 123 and rownum = 1;
--------------------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |     1 |    77 |    31M  (1)| 00:20:50 |
|   1 |  SORT AGGREGATE         |      |     1 |    77 |            |          |
|   2 |   COUNT                 |      |       |       |            |          |
|*  3 |    FILTER               |      |       |       |            |          |
|   4 |     MERGE JOIN CARTESIAN|      |  6131M|   439G|    31M  (1)| 00:20:50 |
|   5 |      TABLE ACCESS FULL  | T1   | 78306 |  3135K|   411   (1)| 00:00:01 |
|   6 |      BUFFER SORT        |      | 78307 |  2752K|    31M  (1)| 00:20:50 |
|   7 |       TABLE ACCESS FULL | T2   | 78307 |  2752K|   409   (1)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("T1"."OBJECT_NAME"="T2"."OBJECT_NAME" OR
              "T1"."DATA_OBJECT_ID"="T2"."DATA_OBJECT_ID" AND "T2"."DATA_OBJECT_ID"
              IS NOT NULL AND "T1"."DATA_OBJECT_ID" IS NOT NULL AND
              "T1"."OBJECT_ID"=123 AND ROWNUM=1)

在执行计划中看到步骤4产生了笛卡尔积连接,成本相当的高,这两个表仅有7万行数据,执行时间超过了5分钟。

数据库中关于NOT、AND、OR的逻辑运算优先级就是按这个顺序进行的,判断是开发人员失误造成的。下面是经过优化后的执行计划。

复制代码
select  count(*) from dev_db.t1 t1,dev_db.t2 t2 where (t1.object_name = t2.object_name or t1.DATA_OBJECT_ID = t2.DATA_OBJECT_ID) and t1.OBJECT_ID = 123 and rownum = 1;
-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |    77 |   822   (1)| 00:00:01 |
|   1 |  SORT AGGREGATE      |      |     1 |    77 |            |          |
|*  2 |   COUNT STOPKEY      |      |       |       |            |          |
|   3 |    NESTED LOOPS      |      |     1 |    77 |   822   (1)| 00:00:01 |
|*  4 |     TABLE ACCESS FULL| T1   |     1 |    41 |   411   (1)| 00:00:01 |
|*  5 |     TABLE ACCESS FULL| T2   |     1 |    36 |   411   (1)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(ROWNUM=1)
   4 - filter("T1"."OBJECT_ID"=123)
   5 - filter("T1"."OBJECT_NAME"="T2"."OBJECT_NAME" OR
              "T2"."DATA_OBJECT_ID" IS NOT NULL AND
              "T1"."DATA_OBJECT_ID"="T2"."DATA_OBJECT_ID" AND "T1"."DATA_OBJECT_ID"
              IS NOT NULL)

在这个执行计划中,t1表作为驱动表,过滤条件是object_id=123,线上这个条件是主键,因为懒没有创建这个主键,所以是全表扫描。

t2表作为被驱动表只匹配到了一条数据。因为STOPKEY的优化,在取到一条数据后SQL停止,无需扫描全部数据,因此执行时间非常短。

总结

本次问题原因是因为一个逻辑运算的优先级判断错误,以至于数据库资源被使用完导致数据库节点被重启。

对于自己拿不准的SQL语句,查阅官方文档是最权威的参考依据。

其次,在测试环境就算只有少量数据也可以看到执行计划是否合理。

最后,上线时SQL语句经过把关,可以最大限度减少SQL语句引发的线上故障。

相关推荐
放下华子我只抽RuiKe53 小时前
FastAPI 全栈后端(三):数据库与 ORM
前端·数据库·react.js·oracle·性能优化·前端框架·fastapi
oyyanghh5 小时前
从Cursor到TRAE的三周vibe coding体验对比
数据库·oracle
Bert.Cai5 小时前
Oracle CONCAT函数详解
数据库·oracle
tiancaijiben7 小时前
阿里云云备份(Cloud Backup)全量对接与使用指南
数据库·oracle
李白的天不白7 小时前
数据库的CEUD
数据库·sql·oracle
山峰哥8 小时前
从全表扫描到覆盖索引:我是怎么干掉慢查询的
数据库·sql·oracle·性能优化·编辑器·深度优先
睡不醒男孩0308231 天前
自建 Prometheus+Grafana 与 CLUP 深度监控 PG 集群有什么区别?
数据库·oracle
德迅云安全-小潘1 天前
网站遭遇SQL注入攻击?应急处置、漏洞修复与长效防御完整方案
网络·sql·oracle
swordbob1 天前
MySQL和Oracle关于读未提交的区别
数据库·mysql·oracle
Nontee1 天前
新手数据库进阶:大白话图解四大隔离级别与底层机制
数据库·oracle