加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

层次查询SQL性能故障不断?给你份可靠的避坑指南!

发布时间:2019-06-07 05:25:43 所属栏目:MySql教程 来源:蒋健
导读:副标题#e# 近期频频遇到层次查询SQL的性能问题,结合历史故障案例,汇总了一些场景connect by常见的性能故障类型,在本文中做个分享。 一、结果中过滤or生成树中过滤 过滤条件放置于where后,为在结果树生成完成后裁剪叶子节点;放置于connect by后,为在生
副标题[/!--empirenews.page--]

近期频频遇到层次查询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. 

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读