没有 Not In 和 In 使用连接的 SQL 查询优化

Posted

技术标签:

【中文标题】没有 Not In 和 In 使用连接的 SQL 查询优化【英文标题】:SQL Query optimization without Not In and In using joins 【发布时间】:2018-07-12 12:28:52 【问题描述】:

我有一个类似下面的查询,我想使用连接重写它。此查询需要 4-5 小时才能在生产环境中执行并返回 GB 的数据。 为了重组它,我使用本地数据库中的一个小数据集检查了它的执行计划,显示成本为 782。 对此,我的同行建议我们不应该在这个查询中使用 IN 和 NOT IN 来提高它的性能。

注意::"SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150"下面的子查询只是在本地尝试,这样我就可以在IN子句中获取一些数据。实际的子查询没有 ROWNUM 和 where 条件中的一些子句。 原始查询 1)

SELECT DISTINCT
                a1.fk_id
            FROM
                tableA a1
            WHERE a1.master_id IN (
                       SELECT DISTINCT
                            a2.master_ref
                        FROM
                            tableB a2
                        WHERE a2.pk_id IN ( SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150)                            
                    ) 
                     AND a1.fk_id NOT IN ( SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150)

我再次重写它,如下所示,这给了我相同的输出,执行计划中的成本与 114 相同。

查询 2)

SELECT DISTINCT
    a1.fk_id
  FROM
      tableA a1, tableB a2 
  WHERE a1.master_id = a2.master_ref 
  AND a2.pk_id IN ( 
    (SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150)
    )
  AND a1.fk_id NOT IN (
    (SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150)
  ) -- This query gives correct result as above.

但是因为我想完全避免 IN 和 NOT IN 子句,并希望尽可能使用 JOIN。我使用 JOIN/LEFT JOIN/EXISTS/NOT EXISTS 尝试了更多查询,但每次我的输出都与所需的不同。

我尝试过的一个查询如下:

查询 3)

SELECT DISTINCT
    a1.fk_id 
  FROM
      tableA a1, ( SELECT a3.pk_id FROM tableB a3 WHERE ROWNUM <= 150 ) pkgObjs, tableB a2
  WHERE a1.ida3b5 = a2.master_ref 
  AND a2.master_id = pkgObjs.pk_id  
  AND a1.fk_id <> pkgObjs.pk_id;
 -- This query is not giving me intended results.

我有几个与此相关的问题::

1) 为什么我的第三个查询(使用连接)没有给我适当的结果? -- 逻辑上似乎是一样的

2) IN 和 NOT IN 在这种情况下是否还有其他选择,我们应该完全避免吗?

3) 就性能而言,第二次查询仍然很昂贵吗?

我是 SQL 新手,我正在尝试分析所有可能的场景。如果我能在使用联接编写此查询时获得一些帮助,那就太好了。

【问题讨论】:

First 使用ROWNUM &lt;= 150 对子查询进行测试没有预期结果,因为您使用了表中的随机 150 行。 第二没有这样的事情没有INNOT IN的查询总是比有它们更好。您必须调查生产执行计划中的问题并做出反应。 感谢您的回复。为了消除由于 ROWNUM 导致的随机值的概率,我创建了一个包含 50000 条记录的 temp_table。现在,当我使用 temp_table 而不是 ROWNUM 子查询时,我可以看到相当大的性能改进。早些时候,有 50000 条记录的查询需要 140 秒才能执行,而 temp_table 只需 12 秒。为什么会这样? 【参考方案1】:

如果我理解得很好,这是您可以使用的最简单的查询:

SELECT
    A.FK_ID
FROM
    TABLEA A, TABLEB B
WHERE
    A.PK_ID = B.PK_ID
    AND A.FK_ID <> B.PK_ID
    --AND ROWNUM <= 150

请注意,ROWNUM 已被注释,因为如果没有订购,您就无法相信它的结果。

如果执行计划成本高,则需要分析索引,有时像下一个这样的小改动,就会产生很大的不同:

SELECT
    B.FK_ID
FROM
    TABLEA B, TABLEB A
WHERE
    B.PK_ID = A.PK_ID
    AND B.PK_ID <> A.FK_ID

【讨论】:

以上是关于没有 Not In 和 In 使用连接的 SQL 查询优化的主要内容,如果未能解决你的问题,请参考以下文章

sql中的in与not in,exists与not exists的区别

sql中的in与not in,exists与not exists的区别

sql中的in与not in,exists与not exists的区别

有没有办法在 SQL 中将 EXCEPT 语句重写为 NOT IN 语句?

浅谈sql中的in与not in,exists与not exists的区别

sql优化,in与exist , not in与not exist 的区别