很多应用都会有类似组织的表,而组织的表通常是典型的层次结构(没有循环节点)。因此,在通过组织进行数据权限控制时,很多人喜欢通过connectby获取组织信息,然后对目标数据进行过滤。在某些情况下,这样写没有什么问题,但在其他情况下,这就是一个大问题。归根结底,这是由connectbyfeature造成的。Oracle无从知晓connectby后会返回多少数据,所以有可能采用了一些你意想不到的算法,结果自然不是你所期望的---很慢。下面,我将讨论在Oracle12.1.0.2中如何处理这样的语句。为了更好理解,我做了3个表:执行SQL:SELECTA.CI,A.ENBAJ02ASCELL_NAMEFROMTDL_CM_CELLA,T_ORG_CELL_SCOPESWHERES.REGION_NAME=A.REGION_NAMEANDS.CITY_NAME=A.CITY_NAMEAND(S.ORG_ID)IN(SELECTIDFROMT_ORGOSTARTWITHID=10102102STARTWITBRIENTYPARENTID1CONNECTIDBORENTID1CONNECT)实际使用的执行计划:无自适应计划(adaptiveplan):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(唯一)|||||||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")注意-----这是一个自适应方案,原因是oracle无法知道connectby后的数字,所以只能被认为是非常大的Amount--一种方法是使用提示解决:SELECT/*+no_merge(x)use_nl(ax)*/A.CI,A.ENBAJ02ASCELL_NAMEFROMTDL_CM_CELLA,(selects.city_name,s.region_namefromT_ORG_CELL_SCOPESWHERE(S.ORG_ID)IN(SELECTIDFROMT_ORGOSTARTWITHID=101021003--1010210--STARTWITHID=1CONNECTBYPARENT_ID=PRIORID))xwherex.REGION_NAME=A.REGION_NAMEANDx.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(唯一)|||||||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")如果一个应用的起始id可能是一个很大的范围,如果你强行使用提示,问题也会出现,所以如果有这样的应用,可以考虑使用oracle12c的自适应特性。如果不是,则必须将不同范围的查询定义为不同的函数并提交给用户。
