从您的公式可以推断出您尝试仅更新一行(或可能的几行)并且您希望快速执行它。
因此,首先认为删除的是table1.col2 上的缺少索引,显然需要使用谓词执行索引访问表:
WHERE
t1.col2 = 'VALUE2'
与子查询类似,您需要在table2.col4 上建立索引(对于谓词t2.col4 = 'VALUE3')
使用此索引设置,您原来的 slow 查询将执行良好(前提是 t1.col2 = 'VALUE2' 只返回几行)。 无需重写花蕊。
你可以检查一下你应该期待的执行计划
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 27 | 4 (0)| 00:00:01 |
| 1 | UPDATE | TABLE1 | | | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| TABLE1 | 1 | 27 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | TABLE1_IDX2 | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| TABLE2 | 1 | 27 | 2 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 7 | BITMAP OR | | | | | |
| 8 | BITMAP CONVERSION FROM ROWIDS | | | | | |
|* 9 | INDEX RANGE SCAN | TABLE2_IDX | | | 1 (0)| 00:00:01 |
| 10 | BITMAP CONVERSION FROM ROWIDS | | | | | |
|* 11 | INDEX RANGE SCAN | TABLE2_IDX2 | | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter( EXISTS (SELECT 0 FROM "TABLE2" "T2" WHERE "T2"."COL3"=:B1 OR
"T2"."COL4"='VALUE3'))
4 - access("T1"."COL2"='VALUE2')
9 - access("T2"."COL3"=:B1)
11 - access("T2"."COL4"='VALUE3')
所以基本上更新是通过一个索引范围扫描,结合FILTER
检查exists 子查询实现为两个索引范围扫描结合BITMAP OR
大型更新的替代解决方案
如果您遇到相反的情况并且谓词 t1.col2 = 'VALUE2' 返回大量行(例如 100K 或更多),您将 1) 绝对不想使用索引访问进行更新(FULL TABLE SCAN 会更有效) 和 2) 您应该将语句拆分在两个更新中。
如果table2包含一行col4 = 'VALUE3'执行
UPDATE table1 t1
SET
t1.col1 = 'VALUE1'
WHERE
t1.col2 = 'VALUE2'
否则执行
UPDATE table1 t1
SET
t1.col1 = 'VALUE1'
WHERE
t1.col2 = 'VALUE2'
AND EXISTS (
SELECT
1
FROM
table2 t2
WHERE
t2.col3 = t1.col3)
split 的原因很简单,第一条语句将使用VALUE2(大数字)更新所有行,并且您希望部署FULL TABLE SCAN。
在第二种情况下,最多更新 30K 行(table2 的基数),您可以使用与上述类似的 FILTERed 执行计划。
当一条语句涵盖两个非常不同的星座时,这是一个典型问题,因此所选的执行计划在一种情况下工作良好,另一种情况下工作不好。
如果你使用两种说法,一种针对每种情况的说法,你就可以避免问题。