国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

層次查詢SQL性能故障不斷?給你份可靠的避坑指南!

數據庫 SQL Server
近期頻頻遇到層次查詢SQL的性能問題,結合歷史故障案例,匯總了一些場景connect by常見的性能故障類型,在本文中做個分享。

近期頻頻遇到層次查詢SQL的性能問題,結合歷史故障案例,匯總了一些場景connect by常見的性能故障類型,在本文中做個分享。

一、結果中過濾or生成樹中過濾

過濾條件放置于where后,為在結果樹生成完成后裁剪葉子節點;放置于connect by后,為在生成樹的過程中裁剪子樹。

頻繁發生的現象是業務邏輯上其實并不需要先生成結果樹再去過濾,由于開發人員對過濾條件放置于不同的位置(where 后,connect by后)產生的過濾效果混淆,導致了低效的性能。

下面這個SQL就是典型案例。用戶反饋,zzzz.SYS_RC_ROUTE_DETAIL表上生產環境就3000+條數據,但SQL語句運行時卻跑不出來結果:

 

  1. select  xxxxx 
  2.   from zzzz.SYS_RC_ROUTE_DETAIL t 
  3.  where t.route_id = (select a.route_id 
  4.                        from xxx.sys_rc_route a, xxx.g_wo_base b 
  5.                       where a.route_id = b.route_id 
  6.                         and b.work_order = 'yyyyyyyyy'
  7.  start with t.node_type = '0' 
  8. connect by nocycle prior next_node_id = node_id 

讓客戶運行了SQL一分鐘后cancel掉,抓取了監視報告如下:

層次查詢SQL性能故障不斷?給你份可靠的避坑指南!

問題點很明顯,表中nextnodeid = node_id的重復值很多,導致了海量的結果集。SQL運行的一分鐘內,connect by尚未把完整的樹生產完成,就已經有了3000W+數據,于是我們開始思考,在邏輯上是否有必要在構建完整的樹后再過濾。

與業務部門溝通后,發現果然不需要。

以下數據可以測試下,3000行數據量,但是count(*) 會非常慢。

 

  1. SQL> create table test1 as 
  2. select 
  3.     mod(rownum,2)                     id, 
  4.     mod(rownum +1 ,2)                  id2 
  5. from 
  6.     dual 
  7. connect by level <= 3000 
  8. ;  2    3    4    5    6    7    8 
  9.  
  10. Table created. 
  11.  
  12. SQL> set timing on 
  13. SQL> select count(*) from test1  where id =0  start with id =0 connect by nocycle prior id = id2 ; 
  14.  
  15.   COUNT(*) 
  16. ---------- 
  17.       1500 
  18.  
  19. Elapsed: 00:09:26.88 
  20. SQL> 

結果中過濾如上所示,用了9分鐘;而生成樹中過濾則只用0.3s:

 

  1. SQL> select count(*) from test1  start with id =0 connect by nocycle prior id = id2 and id = 0 ; 
  2.  
  3.   COUNT(*) 
  4. ---------- 
  5.       1500 
  6.  
  7. Elapsed: 00:00:00.31 

很多情況下,兩種寫法的結果集可能是相同的,如下:

 

  1. create table test2 as 
  2.  select 
  3.       rownum                     id, 
  4.       rownum +1                 id2, 
  5.       rownum + 2               id3 
  6.  from 
  7.      dual 
  8.  connect by level <= 3000; 
  9.  
  10.  SQL> select id from test2 where id3 < 10 start with id = 3 connect by nocycle prior id2 = id; 
  11.  
  12.      ID 
  13.  ---------- 
  14.       1 
  15.       2 
  16.       3 
  17.       4 
  18.       5 
  19.       6 
  20.       7 
  21.  
  22.  7 rows selected. 
  23.  
  24.  SQL> select id from test2  start with id = 1 connect by nocycle prior id2 = id and id3 <10; 
  25.  
  26.      ID 
  27.  ---------- 
  28.       1 
  29.       2 
  30.       3 
  31.       4 
  32.       5 
  33.       6 
  34.       7 
  35.  
  36.  7 rows selected. 

但其實這兩種寫法在語義上差別很大,結果集也可能不相同,如下:

 

  1.   SQL> select id from test2 where id3 = 10 start with id = 3 connect by nocycle prior id2 = id; 
  2.  
  3.     ID 
  4. ---------- 
  5.      8 
  6.  
  7. Elapsed: 00:00:00.13 
  8.  
  9. SQL> select id from test2  start with id = 3 connect by nocycle prior id2 = id and id3=10; 
  10.  
  11.     ID 
  12. ---------- 
  13.      3 
  14.  
  15. Elapsed: 00:00:00.00 

二、CBO估算不準確

層次查詢的SQL語句頻繁出現的問題,就是CBO估算返回結果集偏差,引起執行計劃不準確。雖然表上收集過統計信息,但是CBO對于結果集的估算跟實際值偏差非常大(幾百上千的倍的差距),但是這個也不能全怪CBO,畢竟遞歸查詢有多少層、有多少數據要裁剪,結合起來考慮,結果確實難以估量。

層次查詢SQL性能故障不斷?給你份可靠的避坑指南!

 

層次查詢SQL性能故障不斷?給你份可靠的避坑指南!

對于CBO估算不準的問題,我們考慮了對結果集相對特殊的參數,在SQL文本上做區分,應用識別特殊參數運行帶hint地改造SQL,通過hint來指定返回結果集。這種情況不同于普通的數據傾斜,無法通過baseline給出一個不涉及應用改造的方案。

層次查詢SQL性能故障不斷?給你份可靠的避坑指南!

三、并行處理

層次查詢的SQL直接使用parallel的hint,會遭遇并行串行化的問題,也就是不能真正并行。對于一些重要且耗時長的層次查詢,可以考慮PIPELINED TABLE FUNCTION改寫SQL的方式來實現。

以下腳本測試參考了陳煥生童鞋的blog以及oracle相關文檔(Doc ID 2168864.1):

 

  1. drop table t1; 
  2. -- t1 with 100,000 rows 
  3. create table t1 
  4. as 
  5. select 
  6.     rownum                      id, 
  7.     lpad(rownum, 10, '0')       v1, 
  8.     trunc((rownum - 1)/100)     n1, 
  9.     rpad(rownum, 100)           padding 
  10. from 
  11.     dual 
  12. connect by level <= 100000 
  13.  
  14. begin 
  15.     dbms_stats.gather_table_stats(user,'T1'); 
  16. end
  17.  
  18. select /*+ monitor */ 
  19.     count(*) 
  20. from 
  21.     select 
  22.         CONNECT_BY_ROOT ltrim(id) root_id, 
  23.         CONNECT_BY_ISLEAF is_leaf, 
  24.         level as t1_level, 
  25.         a.v1 
  26.     from t1 a 
  27.     start with a.id <=1000 
  28.     connect by NOCYCLE id = prior id + 1000 
  29. ); 
  30.  
  31. create or replace package refcur_pkg 
  32. AS 
  33.     TYPE R_REC IS RECORD (row_id ROWID); 
  34.     TYPE refcur_t IS REF CURSOR RETURN R_REC; 
  35. END
  36.  
  37. create or replace package connect_by_parallel 
  38. as 
  39.    /*  Naviagates a shallow hiearchy in parallel, where we do a tree walk for each root */ 
  40.  
  41.     CURSOR C1 (p_rowid ROWID) IS     -- Cursor done for each subtree. This select is provided by the customer 
  42.     select  CONNECT_BY_ROOT ltrim(id) root_id, CONNECT_BY_ISLEAF is_leaf, level as t1_level, a.v1 
  43.           from t1 a 
  44.           start with rowid = p_rowid 
  45.           connect by NOCYCLE id = prior id + 1000; 
  46.  
  47.     TYPE T1_TAB is TABLE OF C1%ROWTYPE; 
  48.  
  49.     FUNCTION treeWalk (p_ref refcur_pkg.refcur_t) RETURN T1_TAB 
  50.              PIPELINED 
  51.     PARALLEL_ENABLE(PARTITION p_ref BY ANY); 
  52.  
  53. END connect_by_parallel; 
  54.  
  55. create or replace package body connect_by_parallel 
  56. as  
  57. FUNCTION treeWalk (p_ref refcur_pkg.refcur_t) RETURN T1_TAB 
  58.           PIPELINED PARALLEL_ENABLE(PARTITION p_ref BY ANY
  59. IS 
  60.   in_rec p_ref%ROWTYPE; 
  61. BEGIN 
  62.    execute immediate 'alter session set "_old_connect_by_enabled"=true'
  63.    LOOP -- for each root 
  64.     FETCH p_ref INTO in_rec; 
  65.     EXIT WHEN p_ref%NOTFOUND; 
  66.     FOR c1rec IN c1(in_rec.row_id)  LOOP -- retrieve rows of subtree 
  67.         PIPE ROW(c1rec); 
  68.     END LOOP; 
  69.   END LOOP; 
  70.   execute immediate 'alter session set "_old_connect_by_enabled"=false';  
  71.   RETURN
  72. END  treeWalk; 
  73.  
  74. END connect_by_parallel; 
  75.  
  76. SELECT 
  77.   /*+ monitor */ 
  78.   COUNT(*) 
  79. FROM TABLE(connect_by_parallel.treeWalk (CURSOR 
  80.   (SELECT /*+ parallel (a 100) */ 
  81.     rowid FROM t1 a WHERE id <= 100))) b; 

層次查詢的SQL在整個SQL優化場景中占比相對較小,但這種類型的SQL優化卻往往比較麻煩,本文分享的三個案例均為實戰中總結,對于Oracle層次查詢的SQL優化有極大的借鑒意義,特別是陳煥生提供的做并行的案例,含金量很高,感興趣的童鞋可以測試下。

作者介紹

蔣健,云趣網絡科技聯合創始人,Oracle ACE,11g OCM,多年Oracle設計、管理及實施經驗,精通數據庫優化,Oracle CBO及并行原理。云趣鷹眼監控核心設計和開發者,資深Python Web開發者。

責任編輯:未麗燕 來源: DBAplus社群
相關推薦

2018-07-03 10:49:22

性能故障排查

2024-04-03 12:30:00

C++開發

2024-04-24 13:45:00

2021-02-26 00:46:11

CIO數據決策數字化轉型

2020-12-16 10:00:59

Serverless數字化云原生

2023-05-24 10:06:42

多云實踐避坑

2021-05-07 21:53:44

Python 程序pyinstaller

2021-05-08 12:30:03

Pythonexe代碼

2022-03-04 18:11:16

信服云

2021-02-22 17:00:31

Service Mes微服務開發

2018-01-20 20:46:33

2020-06-12 11:03:22

Python開發工具

2021-04-28 09:26:25

公有云DTS工具

2020-08-26 07:37:25

Nacos微服務SpringBoot

2023-11-01 15:32:58

2018-03-26 11:14:13

程序猿bug代碼

2019-02-12 15:07:42

屏幕參數PC

2019-04-24 17:45:24

微服務容器青云

2020-09-13 09:19:10

LinuxPython3.6

2025-04-10 08:21:17

點贊
收藏

51CTO技術棧公眾號

亚洲精品美女在线观看播放| 欧美日韩国产综合一区二区三区| 韩国国内大量揄拍精品视频| 欧美xxxxxx| 精品欧美aⅴ在线网站| 久草.com| 一区二区三区精品| 在线日韩av观看| 大胆av不用播放器在线播放| 亚洲国产精品国自产拍av| 996这里只有精品| 麻豆精品国产91久久久久久| 日本成人看片网址| 欧美亚洲三级| 你懂的网址一区二区三区| 国产亚洲网站| 日产中文字幕在线精品一区 | 欧美大陆一区二区| 黄色av成人| 亚洲a中文字幕| 欧美日韩午夜| 久久精品日韩| 麻豆久久一区二区| 伊人久久大香线蕉av一区| 久久91精品国产91久久小草| 欧美一区永久视频免费观看| 好男人免费精品视频| 色综合久久综合网| 91在线看黄| 日韩欧美中文字幕制服| 超碰在线cao| 亚洲性猛交xxxxwww| 色综合.com| 欧美一级大胆视频| 亚洲a在线视频| 欧美一区少妇| 成人午夜激情影院| 一区二区三区亚洲| 欧美性xxx| 欧美日韩国产999| 国内精品久久久久久久影视简单| 国产精品网站大全| 亚洲男人影院| 欧美精品自拍视频| 亚洲天堂精品在线观看| 五月激情在线| 欧美一区二区三区免费大片| 欧美日韩视频网站| 99久久精品国产毛片| 日本三级免费观看| 亚洲综合成人在线| www.欧美日本韩国| 一个人看的www久久| 日韩精品丝袜美腿| 国产女人水真多18毛片18精品| 麻豆视频观看网址久久| 亚洲高清在线免费观看| 色呦呦国产精品| 日韩videos| 久久精品国内一区二区三区 | 国内一区二区视频| 黄色一级二级三级| 在线中文字幕一区| 成人免费无遮挡| 日韩免费黄色av| 久久综合五月| 五月天亚洲视频| 欧美日韩午夜影院| 亚洲精品66| 国产精品伊人日日| 99精品黄色片免费大全| 欧美日韩伦理片| 色偷偷av一区二区三区乱| 亚洲一区二区三区| 黄页网站在线观看视频| 在线亚洲人成电影网站色www| 亚洲青青一区| 精品乱色一区二区中文字幕| 国产日韩v精品一区二区| 久久99精品久久| 欧美有码在线观看视频| 国内精品伊人久久久久av一坑| 一级毛片国产| 一本久久综合亚洲鲁鲁| 欧美xxx在线观看| 国产婷婷一区二区三区| 欧美乱熟臀69xxxxxx| 久久精品论坛| 日本美女爱爱视频| 福利微拍一区二区| 哺乳一区二区三区中文视频| 中文字幕第50页| 在线成人午夜影院| 色777狠狠狠综合伊人| 日韩精品免费播放| 日韩经典一区二区三区| 激情综合激情| 成人c视频免费高清在线观看| 色婷婷综合成人av| 午夜在线a亚洲v天堂网2018| 黄色毛片av| 裸体女人亚洲精品一区| 久久99国产精品久久99| 日本中文字幕在线观看| 国产一区二区在线免费视频| 国产亚洲精品免费| 99亚洲伊人久久精品影院| 日韩理论片在线观看| 欧美性猛片aaaaaaa做受| 精品盗摄女厕tp美女嘘嘘| 免费看a级黄色片| 在线视频免费一区二区| 国产一区二区调教| 天天干在线视频论坛| 成人自拍网站| 日本丶国产丶欧美色综合| 国产乱码精品一区二区三区四区| 亚洲77777| 欧美激情欧美狂野欧美精品| 99国产精品久久久久久久久久| 九九热线视频只有这里最精品| 一区二区国产日产| 亚洲第一二三四五区| 免费观看成人av| 波多野结衣中文字幕久久| 欧美日韩在线一二三| 欧美一级片在线观看| 日韩视频在线一区二区三区| 高h视频在线| 国产精品久久久久久久久久直播| 一本大道av一区二区在线播放| 91超碰国产精品| 成人福利在线| 欧美激情导航| 日韩三级中文字幕| 蜜臀精品一区二区三区在线观看 | 欧美日韩中文字幕一区二区三区 | 动漫一区二区| 一区二区三区不卡在线| 精品国产乱码久久久久久影片| 美女视频一区免费观看| 欧美6一10sex性hd| 一二三四中文字幕| 毛片精品免费在线观看| 欧美国产激情一区二区三区蜜月| 丝袜美腿综合| 欧美偷拍视频| 日韩电影大全在线观看| 亚洲图片欧美午夜| 国产欧美精品一区二区色综合朱莉| 天堂俺去俺来也www久久婷婷| 最新av免费在线| 国产亚洲欧美另类一区二区三区| 欧美狂野另类xxxxoooo| 久久99精品久久只有精品| 日韩国产一二三区| 成年人免费视频观看| 亚洲一区亚洲二区| 精品国产凹凸成av人网站| 成人激情黄色小说| 亚州国产精品| 午夜视频在线观看免费视频| 亚洲春色在线视频| 欧美福利视频在线观看| 亚洲一区中文在线| 久久福利精品| 亚洲青青一区| 日本一区高清| 熟女视频一区二区三区| 欧美人在线视频| 在线观看亚洲专区| 国模无码大尺度一区二区三区| 99精品国产一区二区三区2021| 男女网站在线观看| 青青视频免费在线观看| 日本久久久久久久久久久| 在线播放视频一区| 91亚洲精品一区二区乱码| 天天综合网91| 日韩一区二区三区在线免费观看| 国产aa视频| 亚洲精品欧洲精品| 国产成人a亚洲精品| 亚洲第一网站免费视频| 亚洲欧美怡红院| 日韩不卡在线观看日韩不卡视频| 婷婷综合国产| 国产欧美黑人| 丰满少妇又爽又紧又丰满69| 欧美高清性xxxxhd| 97成人超碰免| 精品成人一区二区三区| 亚洲精品视频免费看| 久久电影国产免费久久电影| 国产精品羞羞答答在线观看| 一区二区三区电影大全| 免费在线黄色影片| 久久精品影视大全| 伊人婷婷久久| 成人在线观看av|