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

时间:2017-04-13 16:41:03

标签: sql oracle performance

我在下面看到了SQL外观。问题是表T2太大,下载所有数据需要几个小时(虽然显示前500个结果需要7秒)。有没有人知道如何加速" NOT IN"条款,或替换" NOT IN"通过其他排除方法?非常感谢你!

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

3 个答案:

答案 0 :(得分:3)

您可以使用T1T2表之间的联接来重新定义查询:

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

如果您在连接列上有索引,特别是T2的{​​{1}}列上的索引,这可能会加快速度。

答案 1 :(得分:0)

如果表T1的记录数量非常少,如果表格T2在列B上有索引,那么您所需的访问计划是对T2 中的每条记录T1执行一次索引查找。

预期执行计划使用 NESTED LOOP ANTIJOIN

如果需求已完整且优化程序统计信息是新的,则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行),则查询将停止表演。在这种情况下,所需的访问权限是在每个表上进行一次全扫描

预期计划为 HASH ANTIJOIN

---------------------------------------------------------------------------
| 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中包含或排除T2的所有NULL值,而无需查找df['w2v_sim']=df.apply(lambda x: w2v.n_similarity(x.q1, x.q2), axis=1)

祝你好运!

答案 2 :(得分:0)

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

所以,我修改了如下的查询,速度更快,运行和下载只需10分钟。

WITH T3 AS(从T2选择DISTINCT B)

SELECT T1。*

来自T1左接点T3上T1.A = T3.B

T3在哪里。 B IS NULL且T1.A不为空

UNION ALL

SELECT T1。*

T1.A IS NULL