【发布时间】:2021-06-14 04:31:10
【问题描述】:
我有以下查询
SELECT LkPartProduct.PartID, LkPartProduct.ProductID
FROM LkPartProduct
WHERE LkPartProduct.PartID IN (SELECT WO.PartID FROM WO WHERE WO.WOID = 310000000001549881)
AND LkPartProduct.PartIsRetired = 0
AND LkPartProduct.ProductIsRetired = 0
当我运行此查询时,执行计划显示它在执行合并连接之前返回 LkPartProduct(视图)中的每条记录
见:
| Id | Operation | Name | Rows | Bytes | Cost |
|---|---|---|---|---|---|
| 0 | SELECT STATEMENT | 33 | 1881 | 245M | |
| 1 | MERGE JOIN | 33 | 1881 | 245M | |
| 2 | VIEW | 7309K | 271M | 245M | |
| 3 | WINDOW SORT PUSHED RANK | 7309K | 118G | 245M | |
| 4 | FILTER |
完整的计划可以在这里找到https://pastebin.com/raw/sCRBhZHS
如果我更改该查询以在不查找的情况下过滤 PartID,则该计划更明智。
SELECT LkPartProduct.PartID, LkPartProduct.ProductID
FROM LkPartProduct
WHERE LkPartProduct.PartID IN (310101554)
AND LkPartProduct.PartIsRetired = 0
AND LkPartProduct.ProductIsRetired = 0
| Id | Operation | Name | Rows | Bytes | Cost |
|---|---|---|---|---|---|
| 0 | SELECT STATEMENT | 33 | 1287 | 1212 | |
| 1 | VIEW | 33 | 1287 | 1212 | |
| 2 | WINDOW SORT PUSHED RANK | 33 | 559K | 1212 | |
| 3 | FILTER |
完整计划在这里https://pastebin.com/raw/fc08r1L1
我知道它是将苹果与橙子进行比较,但 MSSQL 中的相同查询可以正常工作,但在 Oracle 中,它似乎总是在如何最好地查询数据方面做出错误的决定。 Logicall 我希望子查询返回 PartID,然后在过滤中使用它。
有什么建议吗?
我尝试将 PartID 粘贴到私有临时表、CTE、JOIN 中,但没有任何乐趣。
根据要求,这里是视图
https://pastebin.com/raw/3n2qqV0Z
如果我运行以下命令只是从 WO 获取 PartID
SELECT WO.PARTID FROM WO WHERE WO.WOID = 310000000001549881
解释计划如下
| Id | Operation | Name | E-Rows | E-Bytes | Cost |
|---|---|---|---|---|---|
| 0 | SELECT STATEMENT | 1 | 18 | 3 | |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED | WO | 1 | 18 | 3 |
| 2 | INDEX RANGE SCAN | IM_WOID_ROUTINGID | 1 | 2 |
如你所料,运行下面的速度很快
SELECT LkPartProduct.PartID, LkPartProduct.ProductID
FROM LkPartProduct
WHERE LkPartProduct.PartID IN (select /*+ PRECOMPUTE_SUBQUERY */ WO.PartID FROM WO WHERE WO.WOID = 310000000001549881)
在这里解释一下
https://pastebin.com/raw/MwtinW3e
一些细节:
WOID 是NUMBER(19)
我有以下索引:
CREATE INDEX I_CID ON WO(CUSTOMERID);
CREATE INDEX I_RFJSID ON WO(RFJOBSTATUSID);
CREATE INDEX I_WO_PARTID ON WO(PARTID);
CREATE INDEX I_WO_RUNNO ON WO(RUNNO, WOID, WONUMBER, PARTID);
CREATE INDEX I_WOREF ON WO(WOREFID);
CREATE INDEX I_WOROUTINGID ON WO(ROUTINGID);
CREATE INDEX IM_WOID_ROUTINGID ON WO(WOID, ROUTINGID);
【问题讨论】:
-
子查询是否应该准确返回 1 行?如果将
IN替换为=会发生什么? -
始终使用限定名称以确保该字段来自您需要的表。可能过滤表中有同名的列
-
@astentx 我已经更新了,所以它在问题中是合格的,那是我在打字时很懒。
-
你能发布视图的定义吗?我的猜测是视图定义中有一些东西阻止了 Oracle 推送谓词。
-
您能否发布完整的计划(包括访问和过滤谓词以及对象名称)?这两个计划的第一步都是过滤器,但一个过滤器可能会过滤掉更多信息,原因尚不清楚。
标签: oracle subquery sql-execution-plan