编辑:我通过引入位置实体提供了附加信息,以明确我为什么尝试使用子查询
在 oracle 11g 数据库中,我有层次结构的元素表,最终将包含几百万行。每行都有指向其父行的索引外键,并且不允许循环。元素也有名称和类型。除此之外,还有另一个实体 - location,它类似于元素(分层,具有指向父级+名称的外键)。顶部元素(你的根)可以在位置(它们通过LocationId连接)。所以有2个实体:
地点:
- 编号 [NUMBER(9,0), PK]
- ParentId [NUMBER(9,0), FK]
- 名称 [VARCHAR2(200)]
元素:
- 编号 [NUMBER(9,0), PK]
- LocationId [NUMBER(9,0), FK]
- ParentId [NUMBER(9,0), FK]
- 类型 ID [NUMBER(9,0), FK]
- 名称 [VARCHAR2(200)]
现在假设表包含以下数据,例如:
地点:
Id | ParentId | Name
----------------------------------
100 | null | TopLocation
101 | 100 | Level1Location
102 | 101 | Level2Location
元素:
Id | LocationId | ParentId | TypeId | Name
----------------------------------------------------
1 | 102 | null | 10 | TopParent
2 | null | 1 | 11 | Level1Child
3 | null | 2 | 11 | Level2Child
我要做的是为元素编写查询,除了基本的 4 个元素列之外,它还返回父 ID、名称和类型 ID 的完整路径 + 顶部元素 位置ID 和名称的完整路径。因此,如果我获取ID 为 3 的元素(此条件也可能因此处未指定的多列而变得复杂)查询将不得不返回:
Id | ParentId | TypeId | Name | IdsPath | TypeIdsPath | NamesPath | LocIdsPath | LocNamesPath
---------------------------------------------------------------------------------------------------------------------------------------------------------------
3 | 2 | 11 | Level2Child | /3/2/1 | /11/11/10 | /Level2Child/Level1Child/TopParent | /102/101/100 | /Level2Location/Level1Location/TopLocation
首先,我编写了oracle 分层查询,它返回位置和元素的所需路径
地点
select
SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from
loc
where
connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
start with Id = 102
元素
select
SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
SYS_CONNECT_BY_PATH(TypeId, '/') TypeIdsPath,
SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from
ele
where
connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
start with Id = 3
当我想将这些查询用作加入基本选择的子查询时,问题就开始了 - 不能用连接条件替换start with condition,因为分层查询比全表扫描:
select
e.*,
elePath.IdsPath,
elePath.TypeIdsPath,
elePath.NamesPath,
locPath.IdsPath as LocIdsPath,
locPath.NamesPath as LocNamesPath
from
ele e
left join (
--full table scan!
select
CONNECT_BY_ROOT(Id) Id,
Id as TopEleId,
SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
SYS_CONNECT_BY_PATH(TypeId, '/') TypeIdsPath,
SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from ele
where
connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
) elePath on elePath.Id = e.Id
left join (
--full table scan!
select
CONNECT_BY_ROOT(Id) Id,
SYS_CONNECT_BY_PATH(Id, '/') IdsPath,
SYS_CONNECT_BY_PATH(Name, '/') NamesPath
from loc
where
connect_by_isleaf = 1
CONNECT BY PRIOR ParentId = e.Id
) locPath on locPath.Id = elePath.TopEleId
where
e.Id = 3
我也不能做标量子查询,因为查询必须返回多个路径,而不仅仅是一个。有什么建议么?我是在朝着正确的方向前进,还是应该在元素表中添加一些字段并缓存我需要的所有路径?(它们不会经常更新)
谢谢!