成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

驚呆,一條SQL竟然讓Oracle奔潰了

運維 數據庫運維
一條sql就能讓oracle掛了,真的是不敢相信啊,前幾天生產上確實出現了這樣一個故障,我們來一起做一個事件回放。

[[381485]]

 本文轉載自微信公眾號「程序員jinjunzhu」,作者jinjunzhu。轉載本文請聯系程序員jinjunzhu公眾號。 jinjunzhu  

一條sql就能讓oracle掛了,真的是不敢相信啊,前幾天生產上確實出現了這樣一個故障,我們來一起做一個事件回放。

系統介紹

系統架構見下圖:

application1和application2是一個分布式系統中的2個應用,application1連接的數據庫是database1,application2連接的數據庫是database2,application2生產的數據要給application1做跑批使用。

application1要獲取database2的數據,并不是通過接口來獲取的,而是直連database2來獲取,因此application1也具有database2庫的讀權限。

database2中有1張表table_b,里面保存的數據是application1跑批需要的數據。application1查找到table_b的數據后,先保存到database1的數據庫表table_a中,等跑批時取出來用。

table_a和table_b的表結構如下:

2個表的主鍵都是字段a,application1查詢出table_b的數據后,會根據主鍵a來判斷這條數據是否存在,如果數據存在,就更新,否則,就插入。

application1使用的orm框架是mybatis,為了減少應用和數據庫的交互,使用了oracle的merge語句。

注意:mybatis相關的文件有5個:

TableAMapper.java

TableBMapper.java

TableAMapper.xml

TableBMapper.xml

TableAEntity.java

熟悉mybatis的同學應該都知道,前兩個java類是sql操作接口類,第3、4兩個文件是存放sql的xml文件,跟前兩個文件對應,最后一個java文件是do類。

事故現場

TableBMapper中有一個方法selectForPage,用來按頁查詢table_b中數據,每頁1萬條數據,之后把這個list結果merge到table_a,看一下代碼:

  1. //從table_b按每頁1萬條來查詢數據 
  2. List<TableAEntity> list = tableBMapper.selectForPage(startPage, 10000); 
  3. //把查到的數據一次性merge到table_a中 
  4. tableAMapper.mergeFromTableB(list); 

我們再看一下TableAMapper.xml中的mergeFromTableB方法,代碼如下:

  1. <update id="mergeFromTableB" parameterType="list"
  2.   <foreach collection="list" item="item" index="index" separator=";" close=";end;" open="begin"
  3.       MERGE INTO table_a ta USING(select #{item.a} as a,#{item.b} as b,#{item.c} as c, #{item.d} as d from dual) tb 
  4.       on (ta.a = tb.a) 
  5.       WHEN MATCHED THEN UPDATE set 
  6.       ta.b=tb.b, 
  7.       ta.c=tb.c, 
  8.       ta.d=tb.d 
  9.       WHEN NOT MATCHED THEN insert
  10.       a, 
  11.       b, 
  12.       c, 
  13.       d 
  14.       ) 
  15.       values ( 
  16.       tb.a, 
  17.       tb.b, 
  18.       tb.c, 
  19.       tb.d 
  20.       ) 
  21.     </foreach> 
  22. </update

注意:為了文章排版,我對表結構做了簡化,真實案例中table_a這張表有60多個字段。

這條sql執行后,我截取部分oracle的日志,如下:

圖中可以看到oracle報了ORA-07445錯誤。

分析日志后發現,sql綁定變量達到了了79010個,而oracle是不允許超過65535個的。

解決方案

前面的分析確定了導致oracle掛掉的原因是綁定變量超過了65535個,那對癥下藥,解決的方案有3個:

業務系統方案

1.循環單條執行merge語句,優點是修改簡單,缺點是業務系統跟數據庫交互太多,會影響跑批任務執行效率。

2.對mergeFromTableB進行分批調用,比如每1000條調用一次merge方法,改造稍微多一點,但是交互會少很多。

DBA方案

給oracle打一個補丁,這個方案需要停服務。

業務方案2明細有優勢,我用這個方案進行了改造,每次1000條,批量merge,代碼如下:

  1. for (int i = 0; i < list.size(); i += 1000) { 
  2.     if (i + 1000 < list.size()) { 
  3.         tableAMapper.mergeFromTableB(list.subList(i, i + 1000)); 
  4.     } else { 
  5.         tableAMapper.mergeFromTableB(list.subList(i, list.size())); 
  6.     } 

新的問題

按照上面的方案改造完成后,數據庫不會奔潰了,但是新的問題出現了。測試的同學發現,每次處理超過1000條數據,非常耗時,有時竟然達到了4分鐘,驚呆。

看打印的批量sql,類似于下面的語句:

  1. begin 
  2. merge into table_a ta USING(...; 
  3. merge into table_a ta USING(...; 
  4. end

分析了一下,雖然放在了一個SQL塊中,但還是單條執行,最后一起提交。

再做一次優化,把上面多條merge語句合成1條。

我的優化思路是創建一張臨時表,先把list中的數據插入到臨時表中,然后用一次merge把臨時表的數據merge進table_a這張表。

oracle的臨時表有2種,一種是會話級別,一種是事務級別:

1.會話級別的臨時表,數據會在整個會話的生命周期中,會話結束,臨時表數據清空;

2.事務級別的臨時表,數據會在整個事務執行過程中,事務結束,臨時表數據清空。

下面看具體實施過程。

1.我們創建一張會話臨時表,SQL如下:

  1. create global temporary table_a_temp on commit delete rows as select * from table_a; 
  2. comment on table_a_temp is 'table_a表臨時表'

2.把table_b查詢到的數據list插入臨時表,需要在 TableAMapper.xml 增加一個方法:

  1. <insert id="batchInsertTemp" parameterType="list"
  2.   insert all 
  3.   <foreach collection="list" index="index" item="item"
  4.     into table_a_temp 
  5.     <trim prefix="(" suffix=")" suffixOverrides="," > 
  6.       a, 
  7.       <if test="item.b != null" > 
  8.         b, 
  9.       </if> 
  10.       <if test="item.c != null" > 
  11.         c, 
  12.       </if> 
  13.       <if test="item.d != null" > 
  14.         d, 
  15.       </if> 
  16.     </trim> 
  17.     <trim prefix="values (" suffix=")" suffixOverrides="," > 
  18.       #{item.a}, 
  19.       <if test="item.b != null" > 
  20.         #{item.b,jdbcType=VARCHAR}, 
  21.       </if> 
  22.       <if test="item.c != null" > 
  23.         #{item.c,jdbcType=VARCHAR}, 
  24.       </if> 
  25.       <if test="item.d != null" > 
  26.         #{item.d,jdbcType=VARCHAR}, 
  27.       </if> 
  28.     </trim> 
  29.   </foreach> 
  30.   select 1 from dual 
  31. </insert

注意:oracle的insert all語句單次插入不能超過1000條。

3.把臨時表的數據merge到table_a中,需要在 TableAMapper.xml 增加一個方法:

  1. <update id="mergeFromTempData"
  2.   MERGE INTO table_a ta 
  3.     USING (select * from table_a_temp) tb 
  4.     on (ta.a = tb.a) 
  5.     WHEN MATCHED THEN UPDATE set 
  6.   ta.b = tb.b, 
  7.   ta.c = tb.c, 
  8.   ta.d = tb.d 
  9.   WHEN NOT MATCHED THEN 
  10.   insert 
  11.   (a, b, c, d) 
  12.   values 
  13.   (tb.a, tb.b, tb.c, tb.d) 
  14. </update

4.最終業務代碼修改如下:

  1. //從table_b查詢 
  2. List<TableAEntity> list = tableBMapper.selectForPage(startPage, 10000); 
  3. //批量插入table_a_temp臨時表 
  4. for (int i = 0; i < list.size(); i += 1000) { 
  5.     if (i + 1000 < list.size()) { 
  6.         tableAMapper.batchInsertTemp(list.subList(i, i + 1000)); 
  7.     } else { 
  8.         tableAMapper.batchInsertTemp(list.subList(i, list.size())); 
  9.     } 
  10. //從table_a_temp把數據merge到table_a 
  11. tableAMapper.mergeFromTempData(); 

總結

在oracle上執行SQL時,如果綁定變量的數量超過了65535,會引發ORA-07445。當然,引發ORA-07445的原因還有其他。

解決這個問題最好的方式是從業務代碼層面進行修改。

也可以讓DBA可以給oracle打一個補丁,但是oracle必須要停服務。

延伸閱讀:

https://community.oracle.com/tech/apps-infra/discussion/2424571/ora-07445-exception-encountered-core-dump-ptmak-106-sigsegv-addres

 

責任編輯:武曉燕 來源: 程序員jinjunzhu
相關推薦

2021-04-16 07:04:53

SQLOracle故障

2021-09-30 08:40:28

Oracle數據庫后端開發

2020-02-09 16:52:02

睡醒公司倒閉

2020-10-26 08:02:28

SQL慢查詢索引

2025-05-20 00:00:00

2020-05-27 11:55:47

Oracle SQL性能優化數據庫

2021-04-09 08:13:14

API網關互聯網

2010-11-15 14:16:09

Oracle表記錄

2023-09-01 14:07:00

ChatGPTGPT數據分析

2017-10-23 15:17:42

技術業務職位

2024-07-29 09:49:00

SQLMySQL執行

2020-07-01 09:07:52

SQL索引語句

2025-05-12 08:27:25

2011-03-23 13:52:09

ORACLESQL十進制

2022-10-12 07:38:24

SQL語句異常

2024-02-01 18:07:37

2021-09-15 06:21:36

Update語句數據庫

2023-03-26 22:42:02

SQL關聯索引

2022-02-11 14:43:53

SQL語句C/S架構

2023-10-06 15:29:07

MySQL數據庫更新
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久草欧美视频 | 国产一级特黄真人毛片 | 国产精品久久久久久久久久 | 狠狠干夜夜草 | 成人美女免费网站视频 | 色吊丝2288sds中文字幕 | 超级碰在线 | 国产一区二区三区在线 | 狠狠色香婷婷久久亚洲精品 | 国产色| 久久精品一区二区 | 国产精品一区在线 | 黄色大片视频 | 毛片av免费在线观看 | 亚洲网站观看 | 羞羞的视频在线 | 国产精品178页 | 精品乱人伦一区二区三区 | 色必久久 | 三级免费 | 久久久久久久久久久久久九 | 夜夜爽99久久国产综合精品女不卡 | 亚洲人成人一区二区在线观看 | 国产福利视频在线观看 | 午夜网站视频 | 午夜爽爽爽男女免费观看 | 国产精品久久久久久久久久久久午夜片 | 亚洲成av人片在线观看无码 | 欧美在线观看黄色 | 伊人影院99| 亚洲激情综合网 | 国产视频亚洲视频 | 国产中文在线 | 亚洲大片在线观看 | 亚洲日本欧美日韩高观看 | 影音先锋欧美资源 | 日韩精品一区二区三区视频播放 | www久久久 | 国产在线一区二区 | 欧美一区二区 | 国产成人艳妇aa视频在线 |