Oracle SQL:如何加速或替换"NOT IN"



我得到了如下所示的SQL。 问题是表 T2 太大,下载所有数据需要数小时(显示前 7 个结果需要 500 秒)。有没有人知道如何加快"NOT IN"条款,或者用其他排除方法替换"NOT IN"?谢谢!

SELECT * 
FROM T1
WHERE  NVL(T1.A,'1') NOT IN (SELECT B FROM T2)

您可以使用T1表和T2表之间的连接来改写查询:

SELECT *
FROM T1
LEFT JOIN T2
ON NVL(T1.A, '1') = T2.B
WHERE T2.B IS NULL

如果您在连接列上有索引,特别是T2B列上有索引,这可能会加快速度。

如果表T1的记录数非常少,并且T2列上有索引B则所需的访问计划是T2T1中对每条记录执行一次索引查找

预期的执行计划使用嵌套循环反连接

如果需求已满足并且优化程序统计信息是最新的,则 Oracle 将自动选择此计划 - 您无需按照其他答案中的建议重新制定查询。

---------------------------------------------------------------------------------
| Id  | Operation              | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |        |     5 |   130 |   106   (0)| 00:00:02 |
|*  1 |  FILTER                |        |       |       |            |          |
|   2 |   NESTED LOOPS ANTI SNA|        |   100 |  2600 |   106   (4)| 00:00:02 |
|   3 |    TABLE ACCESS FULL   | T1     |   100 |  1300 |     2   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN    | T2_IDX |     1 |    13 |     1   (0)| 00:00:01 |
|*  5 |   TABLE ACCESS FULL    | T2     |  4236 | 55068 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE "B" IS NULL))
4 - access("B"=NVL("T1"."A",1))
5 - filter("B" IS NULL)

这个执行计划的问题在于它随着T1行数而线性扩展,即如果T1很大(M 行),查询将停止执行。在这种情况下,所需的访问权限是在每个表上进行一次完全扫描

预期的计划是哈希反联接

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |   100 |  2600 |  5479   (1)| 00:01:38 |
|*  1 |  HASH JOIN ANTI NA |      |   100 |  2600 |  5479   (1)| 00:01:38 |
|   2 |   TABLE ACCESS FULL| T1   |   100 |  1300 |     2   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| T2   | 84722 |  1075K|  5476   (1)| 00:01:38 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("B"=NVL("T1"."A",1))

最后说明 - 您在条件中使用NVL(T1.A,'1')- 表中是否存在值"1"T2?如果这是已知的和常量,您可以简单地包含或排除T1中的所有 NULL 值,而无需查找T2

祝你好运!

感谢大家的帮助。 更多背景: 1. T1 和 T2 都有索引 2. T2 的值为"1",但这不是我们想要的。我们使用NVL("T1")的原因。A",1) 是因为我们希望在最终结果的 A 列中保留空值记录。

因此,我按如下方式修改了查询,它的速度要快得多,运行和下载只需 10 分钟。

T3 为 (从 T2 中选择不同的 B)

选择 T1。

从 T1 向左加入 T1 上的 T3。A = T3.B

其中 T3.B 为空,T1。A 不为空

全部联盟

选择 T1。

其中 T1.A 为空

最新更新