1818IP-服务器技术教程,云服务器评测推荐,服务器系统排错处理,环境搭建,攻击防护等

当前位置:首页 - 数据库 - 正文

君子好学,自强不息!

Oracle中connect by语句的优化

2022-11-22 | 数据库 | 1818ip | 552°c
A+ A-

很多应用中都会有类似组织机构的表,组织机构的表又通常是典型的层次结构(没有循环节点)。于是通过组织控制数据权限的时候,许多人都喜欢通过connect by获得组织信息,然后再过滤目标数据。

在有些情况下,这样写并没有什么问题,但有些情况下,这个就是一个大问题。

归根结底,这是connect by特性导致的,Oracle无法知道connect by之后到底返回多少数据,所以有可能采取一些你所不期望的算法,结果自然不是你所期望的—非常慢。

下面,我就讨论在Oracle 12.1.0.2中如果遇到这样的语句应该如何处理。

为了很好理解,我做了3表:

执行SQL:

SELECTA.CI,A.ENBAJ02ASCELL_NAME
FROMTDL_CM_CELLA,T_ORG_CELL_SCOPES
WHERES.REGION_NAME=A.REGION_NAME
ANDS.CITY_NAME=A.CITY_NAME
AND(S.ORG_ID)IN(SELECTID
FROMT_ORGO
STARTWITHID=101021003--1010210
--STARTWITHID=1
CONNECTBYPARENT_ID=PRIORID)

实际使用的执行计划:

而不会采用自适应计划(adaptive plan):

PlanHashValue:2596385940

-------------------------------------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost|Time|
-------------------------------------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||2622|228114|227|00:00:01|
|1|NESTEDLOOPS||2622|228114|227|00:00:01|
|2|NESTEDLOOPS||2622|228114|227|00:00:01|
|*3|HASHJOIN||1|31|7|00:00:01|
|4|VIEW|VW_NSO_1|1|13|4|00:00:01|
|5|HASHUNIQUE||1|20|4|00:00:01|
|*6|CONNECTBYNOFILTERINGWITHSW(UNIQUE)||||||
|7|TABLEACCESSFULL|T_ORG|75|825|3|00:00:01|
|8|TABLEACCESSFULL|T_ORG_CELL_SCOPE|85|1530|3|00:00:01|
|*9|INDEXRANGESCAN|IDX_TDL_CM_CELL_SCOPE|257||8|00:00:01|
|10|TABLEACCESSBYINDEXROWID|TDL_CM_CELL|2313|129528|220|00:00:01|
-------------------------------------------------------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):
------------------------------------------
*3-access("S"."ORG_ID"="ID")
*6-access("PARENT_ID"=PRIOR"ID")
*6-filter("ID"=101021003)
*9-access("S"."REGION_NAME"="A"."REGION_NAME"AND"S"."CITY_NAME"="A"."CITY_NAME")


Notes
-----
-Thisisanadaptiveplan

原因在于,oracle无法知道connect by之后的数量,所以只能认为是很大的量

有一种方式就是,就是使用提示来解决:

SELECT/*+no_merge(x)use_nl(ax)*/
A.CI,A.ENBAJ02ASCELL_NAME
FROMTDL_CM_CELLA,
(selects.city_name,s.region_name
fromT_ORG_CELL_SCOPES
WHERE(S.ORG_ID)IN
(SELECTID
FROMT_ORGO
STARTWITHID=101021003--1010210
--STARTWITHID=1
CONNECTBYPARENT_ID=PRIORID)

)x
wherex.REGION_NAME=A.REGION_NAME
ANDx.CITY_NAME=A.CITY_NAME

这样计划就是:

PlanHashValue:37846894

---------------------------------------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost|Time|
---------------------------------------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||2313|277560|227|00:00:01|
|1|NESTEDLOOPS||2313|277560|227|00:00:01|
|2|NESTEDLOOPS||2313|277560|227|00:00:01|
|3|VIEW||1|64|7|00:00:01|
|*4|HASHJOIN||1|31|7|00:00:01|
|5|VIEW|VW_NSO_1|1|13|4|00:00:01|
|6|HASHUNIQUE||1|20|4|00:00:01|
|*7|CONNECTBYNOFILTERINGWITHSW(UNIQUE)||||||
|8|TABLEACCESSFULL|T_ORG|75|825|3|00:00:01|
|9|TABLEACCESSFULL|T_ORG_CELL_SCOPE|85|1530|3|00:00:01|
|*10|INDEXRANGESCAN|IDX_TDL_CM_CELL_SCOPE|257||8|00:00:01|
|11|TABLEACCESSBYINDEXROWID|TDL_CM_CELL|2313|129528|220|00:00:01|
---------------------------------------------------------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):
------------------------------------------
*4-access("S"."ORG_ID"="ID")
*7-access("PARENT_ID"=PRIOR"ID")
*7-filter("ID"=101021003)
*10-access("X"."REGION_NAME"="A"."REGION_NAME"AND"X"."CITY_NAME"="A"."CITY_NAME")

如果一个应用的start id可能是一个很大的范围,如果强制使用提示,也会出现问题,所以如果有这样的应用,可以考虑使用oracle 12c的adaptive特性。

如果不行,就必须把不同范围的查询,定义为不同的功能提交给用户。

本文来源:1818IP

本文地址:https://www.1818ip.com/post/10814.html

免责声明:本文由用户上传,如有侵权请联系删除!

发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。