一条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语句引发的线上故障。

相关推荐
jnrjian4 天前
ORA-01017 查找机器名 用户名 以及library cache lock 参数含义
数据库·oracle
TTc_4 天前
oracle中的union和union all有什么区别?
数据库·oracle
山峰哥4 天前
吃透 SQL 优化:告别慢查询,解锁数据库高性能
服务器·数据库·sql·oracle·性能优化·编辑器
南 阳4 天前
Python从入门到精通day37
数据库·python·oracle
轩情吖4 天前
MySQL库的操作
android·数据库·mysql·oracle·字符集·数据库操作·编码集
脱发的老袁4 天前
【数据库】Oracle手动清理归档日志
数据库·oracle
jnrjian4 天前
Oracle 共享池 库缓存下的 Library Cache Lock
数据库·缓存·oracle
新缸中之脑5 天前
在Reddit上探索未满足的需求
数据库·oracle
light blue bird5 天前
产线多并发客户端指令操作场景组件
jvm·oracle·.net·winform
坐吃山猪5 天前
Neo4j04_数据库事务
数据库·oracle·neo4j